Должен ли я давать параметры конструктору или AsyncTask.execute(params)?
Я пытаюсь понять, почему 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);
Еще один вариант, который я рассмотрел, - это предоставить индикатор выполнения конструктору и данным для вызова execute, но я все еще не могу использовать onPreExecute
, поскольку я не знаю максимальное значение. (Я бы предпочел использовать истинный макс, а не устанавливать максимальное значение произвольно и вычислять процент... просто кажется приятнее.)
Где баланс? Что мне делать? Что-то не так с использованием конструктора?
Ответы
Ответ 1
Что касается того, почему документы делают все в методе, это может быть результатом выбора их примера. Обычно вы, скорее всего, расширяете свою AsyncTask и используете только doInBackground()
, а не конструктор.
В любом случае документация:
Наблюдение памяти
AsyncTask гарантирует, что все вызовы обратного вызова синхронизируются в таких способ, при котором следующие операции безопасны без явного синхронизаций.
• Задайте поля элемента в конструкторе или onPreExecute() и обратитесь к ним в > doInBackground (Params...).
• Установите поля-члены в doInBackground (Params...) и обратитесь к ним в onProgressUpdate (Прогресс...) и onPostExecute (Результат).
Это означает, что вы должны быть хорошо с обоими подходами.
И в качестве примечания я использовал AsyncTask
с параметрическим конструктором без проблем, поэтому я могу создать резервную копию содержимого документации.
Кроме того, для вашего конкретного случая, если у параметра ProgressBar
было задано другое максимальное значение, установленное заранее, оно должно быть равно 100. Это означает, что вы можете принять свой конструктор только в ProgressBar
и иметь doInBackground()
принять в данных (который также должен быть переменной-членом). Затем, обновляя прогресс, сделайте
(progress[0]/data.length) * 100
Это не будет идеально, и вы можете преобразовать в double, если хотите повысить точность, но это должно сделать код более легким для понимания.
Ответ 2
На мой взгляд, если я хочу передать некоторые значения для первоначального пользовательского интерфейса, точно так же, как вы упомянули ProgressBar, мне нужно сделать это в OnPreExecute()
. И поскольку OnPreExecute()
не принимает никаких параметров, я предпочитаю поместить значения в конструктор в качестве параметров. Если некоторые значения не относятся к UI, просто нужно указать doInBackground
, например, загружать URL-адреса файлов, я передам их как параметры выполнения.
Итак, в сводке, если значения около UI, передайте их в конструкторе,
если значения только используются в doInBackground, передайте их как параметры выполнения.
Ответ 3
Если вы хотите выполнить работу (требующую параметров) в основном потоке, вам необходимо передать эти параметры в конструктор.
Все, что вы передаете через .execute(), будет запускаться в async-потоке.
Как упоминалось в buptcoder, в основном это касается элементов пользовательского интерфейса, но также операции с дисками/базами данных могут быть критическими для потоков