Как передать в AsyncTask несколько примитивных параметров?


82

Есть связанные вопросы, например, Как передать 2 параметра классу AsyncTask? , но я столкнулся с трудностями, пытаясь безуспешно пытаться передать несколько примитивов в качестве параметров в AsyncTask, поэтому я хочу поделиться тем, что я обнаружил. Эта тонкость не отражена в существующих вопросах и ответах, поэтому я хочу помочь всем, кто столкнется с той же проблемой, что и я, и избавить их от боли.

Вопрос в следующем: у меня есть несколько примитивных параметров (например, два long), которые я хочу передать в AsyncTask для выполнения в фоновом режиме - как это можно сделать? (Мой ответ ... после некоторой борьбы с этим ... можно найти ниже.)


Ответы:


154

Просто оберните свои примитивы в простой контейнер и передайте его в качестве параметра 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);

Это тоже работает. Но я считаю, что приведенные выше варианты проще.
Робгиннесс

10
На самом деле это кажется мне намного приятнее. Я использовал способ Object ... params для этого, и по какой-то причине это просто неудобно или безопасно.
Mafro34

1
Работаю как очаровательный приятель .. Спасибо, что поделился ..!
Deepak S. Gavkar

2
Очень элегантно, нравится.
Sipty

1
@DavidWasser: спасибо за ваше обновление, к тому же данное решение отлично работает!
Мусса

93

Другой способ: вам просто нужно добавить конструктор 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();

Второй способ, подобный ответу Дэвида Вассера.


9
на самом деле это мой любимый из трех способов передачи аргументов разных типов. Нет объекта для приведения и нет необходимости создавать дополнительный класс.
QuickFix

3
Вам нужно вызвать super () в вашем переопределенном конструкторе!
zyamys 02

2
@zyamys зачем здесь нужен super ()? Насколько я понимаю, он будет вызываться автоматически. См. Здесь stackoverflow.com/a/2054040/984263
carthurs

Из вариантов в этой теме мне нравится это больше всего. Никаких вспомогательных классов, этот класс может использоваться сам по себе и описывает свои собственные требования. Никаких загадочных предметов. Благодарю.
Vinnyq12

Это работает. Кажется очень грязным, но мне лень пробовать что-нибудь еще. Не могу поверить, что нет хорошего нативного способа сделать это изначально. Возможно, позже поддержу на Java<(String,Object,int),Void,Void>
Sirens

82

(Строго говоря) НЕ возможно передать несколько примитивов в 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 следующим образом (на примере long):

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

    }
    ...
}

Это более гибкий вариант, но требует явного приведения параметров к соответствующим типам. Если такая гибкость не требуется (например, один тип данных), я рекомендую придерживаться первого варианта, так как он немного более читабелен.


Вы также можете использовать следующее для метода protected LocationItemizedOverlay doInBackground(Object[] objects) и добавить следующее для определения асинхронной задачи. private class MyTask extends AsyncTask<Object, Void, Void>
Хани Сакр

8

Встроенный метод execute принимает массив Params , но все они должны быть определенного типа ... поэтому, если вы просто установите тип PARAM на OBJECT , вы можете передать все, что захотите, если они являются дочерними объектами. ...

private class MyTask extends AsyncTask<Object, Void, Void> {

Затем в вашем doInBackGround вы просто приводите каждый параметр, чтобы вернуться к тому, что вам нужно:

 @Override
 protected void doInBackground(Object... params) {
     Context t = (Context)params[0];
     String a = (String) params[1];
     List<LatLng> list = (List<LatLng>)params[2];
     .
     .
     .

И ваше исполнение просто:

 new MyTask().execute(context,somestring,list_of_points);

Не такая хорошая форма, как упаковка в ваш собственный класс-оболочку, или пакет, или хэш, или что-то в этом роде, потому что вы зависимы от порядка с обеих сторон, но это будет работать. Конечно, вы можете просто сделать свой массив параметром HashMap (,), и вы в основном настраиваете реализацию пакета на этом этапе, но это будет работать.


1
Ребята здесь такие классные, с таким количеством крутых техник, и это была моя любимая!
Джордж Удосен

7

Мне нравится метод Маладжиси, но если нет, не могли бы вы использовать класс Bundle?

 Bundle myBundle = new Bundle();
 myBundle.putInt("foo", foo);
 myBundle.putLong("bar", bar);
 myBundle.putDouble("arple", arple);

Затем просто передайте пакет и распакуйте его в MyTask. Это ужасная идея? Вы избегаете создания настраиваемого класса, и он гибок, если вы решите, что вам нужно будет передать дополнительные параметры позже.

Обновление: прошло довольно много лет с тех пор, как я написал этот ответ, и мне он действительно не нравится сейчас. Я бы не рекомендовал использовать Bundle. Если вам нужно передать несколько параметров в asynctask (или что-то еще), используйте специальный класс, который содержит все ваши параметры сразу. Использование пакета - прекрасное решение проблемы, которой у вас не должно быть. Нет закона против создания специального класса, который будет содержать именно то, что вам нужно, и ничего больше.

Кроме того, почему вы не используете сопрограммы? Asynctasks являются так 2014.


Отличная идея. Однако я предполагаю, что это не поддерживает передачу настраиваемых объектов в doInBackground ()
Джон Уорд

1

Это решается путем создания подклассов. У 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");
    }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.