2

Currently developing a weather application . I wanna strictly observe 2 rules:

  1. MVC Design pattern
  2. Multithreading when I deals with network.

The problem is combining these things into a whole, here are parts of my code:

Weather Class (represent a Weather object) :

public class Weather {
    private int mTimeInSeconds;
    private String mTimeZone;
    private int mTemperature;
    private String mSummary;

    public Weather(int timeInSeconds, String timeZone, int temperature, String summary) {
        mTimeInSeconds = timeInSeconds;
        mTimeZone = timeZone;
        mTemperature = temperature;
        mSummary = summary;
    }

    public String getTime() {
        SimpleDateFormat formatter = new SimpleDateFormat("h:mm a");
        formatter.setTimeZone(TimeZone.getTimeZone(mTimeZone));
        Date dateTime = new Date(mTimeInSeconds * 1000);
        String timeAsString = formatter.format(dateTime);
        return timeAsString;
    }

    public int getTemperature() {
        return mTemperature;
    }

    public String getSummary() {
        return mSummary;
    }
}

Worker Class (do all "dirty" work):

public class Worker {
    private final OkHttpClient mClient = new OkHttpClient();
    private String apiKey = "Secret!11";
    private double latitude = 37.8267;
    private double longitude = -122.423;
    private String forecastUrl = "https://api.forecast.io/forecast/"
                                    +apiKey
                                    +"/"
                                    +latitude
                                    +","
                                    +longitude;

    public void getCurrentWeather() throws Exception {
        final Request request = new Request.Builder()
                            .url(forecastUrl)
                            .build();

        mClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
                Log.v(MainActivity.TAG, e.getMessage());
            }

            @Override
            public void onResponse(Response response) throws IOException {
                try {
                    JSONObject weatherData = new JSONObject(response.body().string());
                    JSONObject currentlyWeather = weatherData.getJSONObject("currently");
                    Log.v(MainActivity.TAG, currentlyWeather.toString());
                } catch (JSONException e) {
                    Log.v(MainActivity.TAG, e.getMessage());
                }
            }
        });
    }
}

Based on my understanding of MVC I put all data and logic around that data in Model (Worker and Weather classes). I wanna to achieve something like this in

MainActivity.java:

...
Worker mWorker = new Worker();
Weather mWeather = mWorker.getWeatherData();
...

2 questions:

  1. Is this the correct design of MVC? (I mean, that all code which somehow work with data separated from the controller which only update view's)

  2. If yes, how I can implement this? I need to return Weather object from Worker, but I can't do this because it's happen on separate thread, I wanna return Weather object to main thread, but have no idea how to implement this.

Marcus
  • 6,697
  • 11
  • 46
  • 89

1 Answers1

1
  1. As far as I know, your Model is your Weather.java class, your MainActivity (and additional added Activities) are your Controller and finally your layout.xml files are your View. So AFAIK yes, this is correctly implemented followed the MVC pattern.
  2. It sounds as your Worker.java class should be of an AsyncTask implementation.

An example using AsyncTask (This is just a stub implementation, see the links below to see fully working examples):

private class WorkerTask extends AsyncTask<String, Void, String> {
    @Override
    protected String doInBackground(String... params) {
        //Network calls go here. This will be done in the background, 
        //in a separate thread

        //Finally, you return your result here to onPostExecute
        return result;
    }

    @Override
    protected void onPostExecute(String result) {
        //This method runs on the main UI thread. Here you update your UI o return data to your caller class.
    }

    @Override
    protected void onPreExecute() {
        //Called before execution
    }

    @Override
    protected void onProgressUpdate(Void... values) {
        //If you want to update your UI with your current progress, that code goes here
    }
}

Finally, you will execute your AsyncTask like this:

new WorkerTask().execute("your_url");

More examples using AsyncTask here, here and here. Official documentation is found here.

Regarding AsyncTask and the MVC design pattern

A downside of this is that the AsyncTask has to be implemented in your MainActivity (or wherever you want to make use of it) which contradicts the MVC design.

A solution to this would be to create a "HTTP caller class" which does the network calls, and which is called in your AsyncTask doInBackground method.

Using this approach, you would be good to go. You would have your controller (MainActivity) executing the AsyncTask (but not doing any actual network calls in MainActivity) creating a new HttpCallerClass, then calling a method which handles the networking. Hence, MVC is preserved.

Community
  • 1
  • 1
Marcus
  • 6,697
  • 11
  • 46
  • 89
  • Thx for the reply, I know about AsyncTask and that's why I don't use it. It breaks MVC design pattern. If I understand correctly your idea of implementation: Implement AsyncTask in MainActivity class, but, doInBackground simply calls method from Model (which does all network-based work behind the scenes). If yes - can this be considered as a correct solution for MVC design pattern? – Vitaly Sulimov Feb 21 '15 at 12:50
  • 1
    See my edit, I address that problem and propose a solution. @VitalySulimov – Marcus Feb 21 '15 at 12:51