我应该给构造函数或AsyncTask.execute(params)提供参数吗?

时间:2013-05-27 01:52:16

标签: android android-asynctask

我试图弄清楚为什么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,因为我不知道最大值。 (我更喜欢使用真正的最大值,而不是任意设置最大值并计算百分比......只是看起来更好。)

余额在哪里?我该怎么办?使用构造函数有什么错误的吗?

3 个答案:

答案 0 :(得分:11)

至于为什么文档在方法中做的一切都可以作为他们的例子选择的结果。通常,您更有可能扩展AsyncTask并仅使用doInBackground(),而不是构造函数。

无论如何,documentation states

  

记忆可观察性

     
     

AsyncTask保证所有回调调用都是同步的   以下操作在没有明确的情况下是安全的方式   同步。

     

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

     

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

这意味着你应该对两种方法都很好。

作为旁注,我使用了AsyncTask和一个没有问题的参数构造函数,因此我可以备份文档所述的内容。

另外,对于您的具体情况,除非ProgressBar预先设置了不同的最大值,否则它应默认为100.这意味着您可以让您的构造函数只接受ProgressBar和让doInBackground()接受数据(也应该是成员变量)。然后在更新进度时,执行

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

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

答案 1 :(得分:2)

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

因此,在摘要中,如果值是关于UI的,请在构造函数中传递它们, 如果值只是在doInBackground中使用,则将它们作为execute的参数传递。

答案 2 :(得分:0)

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

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

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