27

我试图弄清楚为什么 Android 的 AsyncTask 通过传递参数execute以及为什么传递给构造函数似乎没有完成(至少在文档中)。

在我看来,这是最有意义的方式(自然,我正在处理的实际任务不仅仅是一个总和计算器):

public class FooTask extends AsyncTask<Void, Integer, Long> {
    private ProgressBar progressBar;
    private int[] data;

    public FooTask(ProgressBar progressBar, int... data) {
        this.progressBar = progressBar;
        this.data = data;
    }

    protected void onPreExecute() {
        progressBar.setMax(data.length);
        progressBar.setProgress(0);
    }

    protected Long doInBackground(Void... _) {
        long sum = 0;
        for (int i = 0; i < data.length; i++) {
            sum += data[i];
            publishProgress(i);
        }
        return sum;
    }

    protected void onProgressUpdate(Integer... progress) {
        progressBar.setProgress(progress[0]);
    }

    protected void onPostExecute(Long result) {
        Log.i(TAG, "Sum: " + result);
    }
}

这将是这样使用的:

new FooTask(progressBar, 1, 2, 3).execute();

但是,这不是文档所谈论的方式;它使用 的参数execute(),像这样(极端地根本不使用构造函数,但仍然使用一个字段,否则它会太可怕):

public class FooTask extends AsyncTask<Object, Integer, Long> {
    private ProgressBar progressBar;
    private boolean isMaxSettingUpdate = true;

    protected Long doInBackground(Object... params) {
        progressBar = params[0];
        long sum = 0;
        for (int i = 1; i < data.length; i++) {
            sum += (int) data[i];
            publishProgress(i - 1, data.length);
        }
        return sum;
    }

    protected void onProgressUpdate(Integer... progress) {
        progressBar.setMax(progress[1]);
        progressBar.setProgress(progress[0]);
    }

    protected void onPostExecute(Long result) {
        Log.i(TAG, "Sum: " + result);
    }
}

这个任务的执行看起来更像这样:

new FooTask().execute(progressBar, 1, 2, 3);

我考虑的另一种选择是将进度条提供给构造函数并将数据提供给执行调用,但是我仍然无法使用onPreExecute,因为我不知道最大值。(我宁愿使用真正的最大值,而不是任意设置最大值并计算百分比......看起来更好。)

余额在哪里?我应该怎么办?使用构造函数有什么问题吗?

4

3 回答 3

12

至于为什么文档在方法中做所有事情可能是由于他们的示例选择。通常,您更有可能扩展您的 AsyncTask 并且只使用doInBackground(),而不是构造函数。

无论如何,文档指出

内存可观察性


AsyncTask 保证所有回调调用都以这样一种方式同步,即以下操作在没有显式同步的情况下是安全的。

•在构造函数或onPreExecute() 中设置成员字段,并在> doInBackground(Params...) 中引用它们。

• 在doInBackground(Params...) 中设置成员字段,并在onProgressUpdate(Progress...) 和onPostExecute(Result) 中引用它们。

这意味着你应该擅长这两种方法。

附带说明一下,我使用AsyncTask带有参数的构造函数没有问题,因此我可以备份文档所述的内容。

此外,对于您的特定情况,除非ProgressBar事先设置了不同的最大值,否则它应该默认为 100。这意味着您可以让构造函数仅在数据ProgressBardoInBackground()接受并在数据中接受(这也应该是成员变量)。然后在更新进度时,执行

(progress[0]/data.length) * 100

它不会是完美的,如果你想提高准确性,你可以转换为 double,但这应该使代码更容易理解。

于 2013-05-27T02:02:38.270 回答
2

在我看来,如果我想传递一些值来初始化 UI,就像你提到的 ProgressBar,我需要在OnPreExecute(). 而且因为OnPreExecute()不接受任何参数,我更喜欢将值作为参数放在构造函数中。如果某些值与 UI 无关,只需要 in doInBackground,例如文件的下载 url,我会将它们作为执行参数传递。

所以,总而言之,如果值是关于 UI 的,则将它们传递给构造函数,如果值仅用于 doInBackground,则将它们作为执行的参数传递。

于 2013-05-27T02:18:44.343 回答
0

如果你想在主线程上工作(需要参数),你必须将这些参数传递给构造函数。

您通过 .execute() 传递的所有内容都将在异步线程上运行。

正如 buptcoder 提到的,主要是关于 UI 的东西,但磁盘/数据库操作也可能是线程关键的

于 2014-05-12T14:23:26.400 回答