Як можна передати кілька примітивних параметрів в 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.