Как вы можете передать несколько примитивных параметров в AsyncTask?
Есть связанные вопросы, такие как Как я могу передать 2 параметра классу AsyncTask?, но я столкнулся с трудностью тщетной попытки передать несколько примитивов в качестве параметров AsyncTask, поэтому я хочу поделиться тем, что обнаружил. Эта тонкость не отражена в существующих вопросах и ответах, поэтому я хочу помочь всем, кто сталкивается с той же проблемой, что и я, и избавить их от боли.
Вопрос заключается в следующем: у меня есть несколько примитивных параметров (например, два long), которые я хочу передать AsyncTask для выполнения в фоновом режиме - как это можно сделать? (Мой ответ... после некоторой борьбы с ним... можно найти ниже.)
6 ответов
Строго говоря, невозможно передать несколько примитивов в AsyncTask. Например, если вы хотите выполнить myTask.execute(long1, long2)
и попытаться настроить private class myTask extends AsyncTask<long, Void, Void>
с помощью соответствующего метода:
@Override
protected LocationItemizedOverlay doInBackground(long... params) {...}
Ваша IDE, вероятно, будет жаловаться на необходимость переопределения метода супертипа. Обратите внимание, что вы используете так называемую сигнатуру метода Varargs для doInBackground
, где (long... params)
все равно что сказать: "Я принимаю переменное число long, хранящихся в виде массива с именем params. Я не совсем понимаю, что вызывает жалобу компилятора /IDE, но я думаю, что это связано с тем, как универсальный класс Params
определено.
В любом случае, можно без проблем достичь желаемого, если вы правильно приведете свои примитивы к их соответствующим не примитивным оболочкам (например, int => Integer, long => Long и т. Д.). На самом деле вам не нужно явно приводить ваши примитивы к не примитивам. Java, кажется, справится с этим для вас. Вам просто нужно настроить ASyncTask следующим образом (для примера longs):
private class MyTask extends AsyncTask<Long, Void, Void> {
@Override
protected void doInBackground(Long... params) {
// Do stuff with params, for example:
long myFirstParam = params[0]
}
...
}
Затем вы можете использовать этот класс, как вы изначально предполагали, например:
MyTask myTask = new MyTask();
myTask.execute(long1, long2);
Или для любого количества примитивов, которые вы хотели бы, ПРЕДОСТАВЛЯЕТСЯ, ЧТО ОНИ ОДИН ТО ЖЕ ТИПА. Если вам нужно передать несколько типов примитивов, это также можно сделать, но вам нужно будет изменить вышеперечисленное так:
private class MyTask extends AsyncTask<Object, Void, Void> {
@Override
protected void doInBackground(Object... params) {
// Do stuff with params, for example:
long myLongParam = (Long) params[0];
int myIntParam = (Integer) params[1];
}
...
}
Это более гибко, но требует явного приведения параметров к их соответствующим типам. Если такая гибкость не требуется (т. Е. Один тип данных), я рекомендую придерживаться первого варианта, так как он немного более читабелен.
Просто оберните ваши примитивы в простой контейнер и передайте это в качестве параметра AsyncTask, например так:
private static class MyTaskParams {
int foo;
long bar;
double arple;
MyTaskParams(int foo, long bar, double arple) {
this.foo = foo;
this.bar = bar;
this.arple = arple;
}
}
private class MyTask extends AsyncTask<MyTaskParams, Void, Void> {
@Override
protected void doInBackground(MyTaskParams... params) {
int foo = params[0].foo;
long bar = params[0].bar;
double arple = params[0].arple;
...
}
}
Назовите это так:
MyTaskParams params = new MyTaskParams(foo, bar, arple);
MyTask myTask = new MyTask();
myTask.execute(params);
Другой способ: вам просто нужно добавить конструктор MyTask в ваш класс MyTask:
private class MyTask extends AsyncTask<String, Void, Void> {
int foo;
long bar;
double arple;
MyTask(int foo, long bar, double arple) {
// list all the parameters like in normal class define
this.foo = foo;
this.bar = bar;
this.arple = arple;
}
...... // Here is doInBackground etc. as you did before
}
Тогда позвони
new MyTask(int foo, long bar, double arple).execute();
Второй способ, как ответ Дэвида Вассера.
Встроенный метод execute принимает массив Params, но все они должны быть определенного типа... поэтому, если вы просто установите тип PARAM в OBJECT, вы можете передать все, что захотите, пока они являются дочерними объектами....
private class MyTask extends AsyncTask<Object, Void, Void> {
Затем в вашем doInBackGround вы просто приводите каждый параметр к тому, что вам нужно:
@Override
protected void doInBackground(Object... params) {
Context t = (Context)parms[0];
String a = (String) params[1];
List<LatLng> list = (List<LatLng>)params[2];
.
.
.
И ваше выполнение просто:
new MyTask().execute(context,somestring,list_of_points);
Не такая хорошая форма, как упаковка в свой собственный класс-обертку, или в пакет, или в хэш, или что-то еще, потому что вы зависимы от порядка с обеих сторон, но это будет работать. Конечно, вы можете просто сделать свой массив параметром HashMap(,), и вы в основном настраиваете реализацию пакета в этот момент, но это будет работать.
Мне нравится метод Маладжизи, но если нет, не могли бы вы использовать класс Bundle?
Bundle myBundle = new Bundle();
myBundle.putInt("foo", foo);
myBundle.putLong("bar", bar);
myBundle.putDouble("arple", arple);
Затем просто передайте пакет и распакуйте его внутри MyTask. Это ужасная идея? Вы избегаете создания пользовательского класса, и он гибок, если решит, что вам нужно передать дополнительные параметры позже.
Это решается с помощью подклассов. У Google есть пример решения этой проблемы (подклассы) в официальной документации Android AsyncTask:
http://developer.android.com/reference/android/os/AsyncTask.html
Пример:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}