Як можна передати кілька примітивних параметрів в AsyncTask?


82

Є відповідні запитання, наприклад, Як я можу передати 2 параметри до класу AsyncTask? , але я зіткнувся з труднощами марної спроби передати декілька примітивів як параметрів в AsyncTask, тому я хочу поділитися тим, що виявив. Ця тонкість не врахована в існуючих питаннях та відповідях, тому я хочу допомогти кожному, хто зіткнувся з тією ж проблемою, що і я, і врятувати їм біль.

Питання в наступному: у мене є кілька примітивних параметрів (наприклад, два довгих значення), які я хочу передати в 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
Працюємо як привабливий приятель .. Дякуємо за обмін ..!
— Діпак С. Гавкар

2
Дуже елегантно, люблю це.
— Сіпті

1
@DavidWasser: подяка за ваше оновлення, крім того, наведене рішення чудово працює!
— Moussa,

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,

2
@zyamys чому тут потрібен супер ()? Як я розумію, він буде викликаний автоматично. Дивіться тут 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)все одно, що сказати: "Я приймаю змінну кількість лонгів, що зберігається як масив, який називається 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];

    }
    ...
}

Це більш гнучко, але воно вимагає чіткого приведення параметрів до відповідних типів. Якщо ця гнучкість не потрібна (тобто окремий тип даних), я рекомендую дотримуватися першого варіанту, оскільки він трохи читабельніший.


Ви також можете використовувати наступне для методу 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. Це страшна ідея? Ви уникаєте створення власного класу, і він гнучкий, якщо ви вирішите, що пізніше потрібно буде передавати додаткові параметри.

Оновлення: Минуло досить багато років з того часу, як я написав цю відповідь, і зараз мені це дуже не подобається. Я б рекомендував не використовувати набір. Якщо вам потрібно передати кілька параметрів в асинктаск (або щось інше, насправді), використовуйте спеціальний клас, який вміщує всі ваші параметри одночасно. Використання набору - це прекрасне рішення проблеми, якої у вас не повинно бути. Не існує закону, що забороняє створювати власний клас, щоб вміщати саме те, що вам потрібно, і нічого іншого.

Крім того, чому ви не використовуєте спільні програми? Асинктакти - це 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.