Android,从网络获取数据并更新 UI(多线程和 MVC 设计模式)

Android, get data from web and update UI (Multi-threading and MVC design pattern)

目前正在开发天气应用程序。我要严格遵守两条规则:

  1. MVC 设计模式
  2. 当我处理网络时多线程。

问题是将这些东西组合成一个整体,这是我的部分代码:

天气Class(表示一个天气对象) :

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;
    }
}

工人Class(完成所有"dirty"工作):

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());
                }
            }
        });
    }
}

根据我对 MVC 的理解,我将围绕该数据的所有数据和逻辑放在模型(Worker 和 Weather 类)中。我想在

中实现这样的目标

MainActivity.java:

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

2 个问题:

  1. 这是MVC的正确设计吗? (我的意思是,所有以某种方式处理与仅更新视图的控制器分离的数据的代码)

  2. 如果是,我该如何实现?我需要 return 天气对象 来自 Worker, 但是 我不能这样做,因为它发生在单独的线程上,我想 return Weather 对象到主线程,但不知道如何实现它。

  1. 据我所知,您的 M模型就是您的 Weather.java class,您的 MainActivity(以及额外添加的 Activity)就是您的 C控制器和 最后,您的 layout.xml 文件就是您的 View。所以 AFAIK 是的, 这是按照 MVC 模式正确实现的。
  2. 听起来你的 Worker.java class 应该是 AsyncTask 执行。

使用 AsyncTask 的示例(这只是一个存根实现,请参阅下面的链接以查看完整的工作示例):

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
    }
}

最后,您将像这样执行 AsyncTask:

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

使用 AsyncTask 的更多示例 here, here and here。 找到官方文档 here.

关于AsyncTask和MVC设计模式

这样做的缺点是 AsyncTask 必须在您的 MainActivity(或您想要使用它的任何地方)中实现,这与 MVC 设计相矛盾。

解决此问题的方法是创建一个 "HTTP caller class" 进行网络调用,并在您的 AsyncTask doInBackground 方法中调用。

使用这种方法,您就可以开始了。您可以让您的控制器 (MainActivity) 执行 AsyncTask(但不在 MainActivity 中进行任何实际的网络调用)创建一个新的 HttpCallerClass,然后调用一个处理网络的方法。因此,保留了 MVC。