Как передать переменные в и из AsyncTasks? - PullRequest
15 голосов
/ 28 марта 2012

Я не тратил много времени на работу с AsyncTasks в Android. Я пытаюсь понять, как передавать переменные в и из класса. Синтаксис:

class MyTask extends AsyncTask<String, Void, Bitmap>{

     // Your Async code will be here

}

это немного путает с синтаксисом < > в конце определения класса. Никогда не видел такого типа синтаксиса раньше. Кажется, я ограничен только передачей одного значения в AsyncTask. Я ошибаюсь, предполагая это? Если мне нужно еще пройти, как мне это сделать?

Кроме того, как вернуть значения из AsyncTask?

Это класс, и когда вы хотите его использовать, вы вызываете new MyTask().execute(), но фактический метод, который вы используете в классе, это doInBackground(). Так где вы на самом деле что-то возвращаете?

Ответы [ 5 ]

45 голосов
/ 28 марта 2012

Примечание. Вся информация ниже доступна на Android-разработчиках Справочная страница AsyncTask .Заголовок Usage имеет пример.Также обратите внимание на безболезненную запись в блоге для разработчиков Android .

Взгляните на исходный код AsynTask .


Забавная запись < > позволяет настроить асинхронную задачу.Скобки используются для помощи в реализации обобщений в Java .

Существует 3 важных части задачи, которые вы можете настроить:

  1. Тип передаваемых параметров - любое число, которое вы хотите
  2. Тип для того, что вы используете для обновления индикатора выполнения / индикатора
  3. Тип для того, что вы возвращаете однажды, выполненный с фоновой задачей

И помните, что любой из вышеперечисленных может быть интерфейсами .Вот как вы можете передавать несколько типов по одному и тому же вызову!

Типы этих трех вещей помещаются в угловые скобки:

<Params, Progress, Result>

Так что если вы собираетесь передать вURL s и используйте Integers для обновления хода выполнения и возврата логического значения, указывающего на успешность, которое вы напишите:

public MyClass extends AsyncTask<URL, Integer, Boolean> {

В этом случае, если вы загружаете, например, растровые изображения, вы будете обрабатывать то, что делаетес растровыми изображениями в фоновом режиме.Вы также можете просто вернуть HashMap из битмапов, если хотите.Также помните, что переменные-члены, которые вы используете, не ограничены, поэтому не чувствуйте себя слишком привязанными к параметрам, прогрессу и результату.

Для запуска AsyncTask создайте его экземпляр, а затем execute последовательно или впараллельно.В исполнении вы передаете переменные.Вы можете передать более одного.

Обратите внимание, что вы не звоните doInBackground() напрямую.Это потому, что это нарушит магию AsyncTask, а именно то, что doInBackground() выполняется в фоновом потоке.Вызов его непосредственно как есть, заставит его работать в потоке пользовательского интерфейса.Таким образом, вместо этого вы должны использовать форму execute().Задача execute() состоит в том, чтобы запустить doInBackground() в фоновом потоке, а не в потоке пользовательского интерфейса.

Работа с нашим примером сверху.

...
myBgTask = new MyClass();
myBgTask.execute(url1, url2, url3, url4);
...

onPostExecute будетсрабатывает, когда все задачи после выполнения завершены.

myBgTask1 = new MyClass().execute(url1, url2);
myBgTask2 = new MyClass().execute(urlThis, urlThat);

Обратите внимание, как вы можете передать несколько параметров в execute(), который передает несколько параметров в doInBackground().Это происходит с помощью varargs (вы знаете, как String.format(...). Многие примеры показывают только извлечение первых параметров с помощью params[0], но вы должны убедитесь, что вы получили все параметры . Если вы передаете URL, это будет (взято из примера AsynTask, есть несколько способов сделать это):

 // This method is not called directly. 
 // It is fired through the use of execute()
 // It returns the third type in the brackets <...>
 // and it is passed the first type in the brackets <...>
 // and it can use the second type in the brackets <...> to track progress
 protected Long doInBackground(URL... urls) 
 {
         int count = urls.length;
         long totalSize = 0;

         // This will download stuff from each URL passed in
         for (int i = 0; i < count; i++) 
         {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
         }

         // This will return once when all the URLs for this AsyncTask instance
         // have been downloaded
         return totalSize;
 }

Если вы собираетесь выполнять несколько задач bg, то вы должны учитывать, что вышеуказанные вызовы myBgTask1 и myBgTask2 будут выполняться в последовательности . Это хорошо, если один вызов зависит от другого,но если вызовы независимы - например, вы загружаете несколько изображений, и вам все равно, какие из них поступают первыми - тогда вы можете делать вызовы myBgTask1 и myBgTask2 параллельно с THREAD_POOL_EXECUTOR:

myBgTask1 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url1, url2);
myBgTask2 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urlThis, urlThat);

Примечание:

Пример

Вот пример AsyncTask, который может принимать столько типов, сколько вы хотитена одну и ту же команду execute(). Ограничение - каждый тип долженТот же интерфейс:

public class BackgroundTask extends AsyncTask<BackgroundTodo, Void, Void>
{
    public static interface BackgroundTodo
    {
        public void run();
    }

    @Override
    protected Void doInBackground(BackgroundTodo... todos)
    {
        for (BackgroundTodo backgroundTodo : todos)
        {
            backgroundTodo.run();

            // This logging is just for fun, to see that they really are different types
            Log.d("BG_TASKS", "Bg task done on type: " + backgroundTodo.getClass().toString());
        }
        return null;
    }
}

Теперь вы можете сделать:

new BackgroundTask().execute(this1, that1, other1); 

Где каждый из этих объектов имеет свой тип!(который реализует тот же интерфейс)

9 голосов
/ 24 марта 2015

Я понимаю, что это поздний ответ, но вот что я делал в последнее время.

Когда мне нужно передать кучу данных в AsyncTask, я могу либо создать свой собственный класс, передать его и получить доступ к его свойствам, например:

public class MyAsyncTask extends AsyncTask<MyClass, Void, Boolean> {

    @Override
    protected Boolean doInBackground(MyClass... params) {

        // Do blah blah with param1 and param2
        MyClass myClass = params[0];

        String param1 = myClass.getParam1();
        String param2 = myClass.getParam2();

        return null;
    }
}

и затем получите к нему доступ следующим образом:

AsyncTask asyncTask = new MyAsyncTask().execute(new MyClass());

или я могу добавить конструктор в мой класс AsyncTask, например:

public class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {

    private String param1;
    private String param2;

    public MyAsyncTask(String param1, String param2) {
        this.param1 = param1;
        this.param2 = param2;
    }

    @Override
    protected Boolean doInBackground(Void... params) {

        // Do blah blah with param1 and param2

        return null;
    }
}

, а затем получить к нему доступ следующим образом:

AsyncTask asyncTask = new MyAsyncTask("String1", "String2").execute();

Надеюсь, это поможет!

2 голосов
/ 28 марта 2012

Поскольку вы можете передавать массив объектов в квадратных скобках, это лучший способ передать данные, на основе которых вы хотите выполнить обработку в фоновом режиме.

Вы можете передать ссылку на свою деятельность или представление в Конструкторе и использовать ее для передачи данных обратно в свою деятельность

class DownloadFilesTask extends AsyncTask<URL, Integer, List> {
    private static final String TAG = null;
    private MainActivity mActivity;
    public DownloadFilesTask(MainActivity activity) {
        mActivity = activity;
        mActivity.setProgressBarIndeterminateVisibility(true);
    }

    protected List doInBackground(URL... url) {
        List output = Downloader.downloadFile(url[0]);
        return output;
    }

    protected void onProgressUpdate(Integer... progress) {
        setProgressPercent(progress[0]);
    }

    private void setProgressPercent(final Integer integer) {
        mActivity.setProgress(100*integer);
    }

    protected void onPostExecute(List output) {

        mActivity.mDetailsFragment.setDataList((ArrayList<Item>) output);

        //you could do other processing here
    }
}
0 голосов
/ 18 ноября 2015

Передача простой строки:

 public static void someMethod{ 
     String [] variableString= {"hello"};
     new MyTask().execute(variableString);
}

static class MyTask extends AsyncTask<String, Integer, String> {

        // This is run in a background thread
        @Override
        protected String doInBackground(String... params) {
            // get the string from params, which is an array
            final String variableString = params[0];

            Log.e("BACKGROUND", "authtoken: " + variableString);

            return null;
        }
    }
0 голосов
/ 28 марта 2012

В качестве альтернативы, вы можете просто использовать обычный поток и обработчик для отправки данных обратно в поток пользовательского интерфейса, переопределив функцию handlemessage.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...