Поиск…


параметры

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

Основное использование

В действиях и службах Android большинство обратных вызовов запускаются в основном потоке . Это упрощает обновление пользовательского интерфейса, но выполнение основных задач с процессором или I / O в основном потоке может привести к тому, что ваш пользовательский интерфейс приостановится и перестанет отвечать ( официальная документация о том, что происходит).

Вы можете исправить это, поставив эти более тяжелые задачи на фоновый поток.

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

Методы, которые можно переопределить при расширении AsyncTask :

  • onPreExecute() : вызывается в потоке пользовательского интерфейса перед выполнением задачи
  • doInBackground() : вызывается в фоновом потоке сразу после того, как onPreExecute() завершает выполнение.
  • onProgressUpdate() : вызывается в потоке пользовательского интерфейса после вызова publishProgress(Progress...) .
  • onPostExecute() : вызывается в потоке пользовательского интерфейса после завершения фоновых вычислений

пример

public class MyCustomAsyncTask extends AsyncTask<File, Void, String> {

    
    @Override
    protected void onPreExecute(){
        // This runs on the UI thread before the background thread executes.
        super.onPreExecute();
        // Do pre-thread tasks such as initializing variables. 
        Log.v("myBackgroundTask", "Starting Background Task");  
    }

    @Override
    protected String doInBackground(File... params) {
        // Disk-intensive work. This runs on a background thread.
        // Search through a file for the first line that contains "Hello", and return
        // that line.
        try (Scanner scanner = new Scanner(params[0])) {
            while (scanner.hasNextLine()) {
                final String line = scanner.nextLine();
                publishProgress(); // tell the UI thread we made progress

                if (line.contains("Hello")) {
                    return line;
                }
            }
            return null;
        }
    }

    @Override
    protected void onProgressUpdate(Void...p) {
        // Runs on the UI thread after publishProgress is invoked
        Log.v("Read another line!")
    }        

    @Override
    protected void onPostExecute(String s) {
        // This runs on the UI thread after complete execution of the doInBackground() method
        // This function receives result(String s) returned from the doInBackground() method.
        // Update UI with the found string.
        TextView view = (TextView) findViewById(R.id.found_string);
        if (s != null) {
            view.setText(s);
        } else {
            view.setText("Match not found.");
        }
    }

}

Использование:

MyCustomAsyncTask asyncTask = new MyCustomAsyncTask<File, Void, String>();
// Run the task with a user supplied filename.
asyncTask.execute(userSuppliedFilename);

или просто:

new MyCustomAsyncTask().execute(userSuppliedFilename);

Заметка

При определении AsyncTask мы можем передавать три типа между скобками < > .
Определяется как <Params, Progress, Result> (см. Раздел «Параметры» )

В предыдущем примере мы использовали типы <File, Void, String> :

AsyncTask<File, Void, String>
// Params has type File
// Progress has unused type
// Result has type String

Void используется, если вы хотите пометить тип как неиспользуемый.

Обратите внимание, что вы не можете передавать примитивные типы (т. int , float и еще 6 других) в качестве параметров. В таких случаях вы должны передать свои классы-оболочки , например Integer вместо int , или Float вместо float .

Жизненный цикл AsyncTask и Activity

AsyncTasks не соответствуют жизненному циклу экземпляров действий. Если вы запустите AsyncTask внутри Activity и вы повернете устройство, действие будет уничтожено, и будет создан новый экземпляр. Но AsyncTask не умрет. Он будет продолжаться до тех пор, пока он не завершится.

Решение: AsyncTaskLoader

Одним из подклассов Loaders является AsyncTaskLoader. Этот класс выполняет ту же функцию, что и AsyncTask, но намного лучше. Он легче справляется с изменениями конфигурации деятельности и ведет себя в жизненных циклах фрагментов и действий. Приятно, что AsyncTaskLoader можно использовать в любой ситуации, в которой используется AsyncTask. В любое время данные должны загружаться в память для Activity / Fragment для обработки, AsyncTaskLoader может выполнять работу лучше.

Отмена AsyncTask

YourAsyncTask task = new YourAsyncTask();
task.execute();
task.cancel();

Это не остановит вашу задачу, если она была в процессе, она просто устанавливает отмененный флаг, который можно проверить, проверив возвращаемое значение isCancelled() (если ваш код запущен в данный момент), выполнив следующие действия:

class YourAsyncTask extends AsyncTask<Void, Void, Void> {
    @Override
    protected Void doInBackground(Void... params) {
        while(!isCancelled()) {
            ... doing long task stuff
            //Do something, you need, upload part of file, for example
            if (isCancelled()) {    
                return null; // Task was detected as canceled
            }
            if (yourTaskCompleted) {
                return null;
            }
        }
    }
}

Заметка

Если AsyncTask отменяется, а doInBackground(Params... params) все еще выполняется, тогда метод onPostExecute(Result result) НЕ будет вызываться после doInBackground(Params... params) . AsyncTask вместо этого вызовет onCancelled(Result result) чтобы указать, что задача была отменена во время выполнения.

Успех публикации

Иногда нам необходимо обновить ход вычислений, выполненный с помощью AsyncTask . Этот прогресс может быть представлен строкой, целым числом и т. Д. Для этого мы должны использовать две функции. Во-первых, нам нужно установить функцию onProgressUpdate , тип параметра которой совпадает с параметром второго типа нашей AsyncTask .

class YourAsyncTask extends AsyncTask<URL, Integer, Long> {
    @Override
    protected void onProgressUpdate(Integer... args) {
        setProgressPercent(args[0])
    }
}

Во-вторых, мы должны использовать функцию publishProgress обязательно doInBackground функции doInBackground , и это все, предыдущий метод выполнит всю работу.

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));
     }
     return totalSize;
 }

Загрузить изображение с помощью AsyncTask в Android

В этом руководстве объясняется, как загрузить изображение с помощью AsyncTask в Android. Пример ниже загружает изображение, пока отображается индикатор выполнения во время загрузки.

Понимание Android AsyncTask

Задача Async позволяет реализовать MultiThreading, не втирая руки в потоки. AsyncTask обеспечивает правильное и простое использование потока пользовательского интерфейса. Он позволяет выполнять фоновые операции и передавать результаты в потоке пользовательского интерфейса. Если вы делаете что-то изолированное, связанное с пользовательским интерфейсом, например, загружая данные в список в списке, используйте AsyncTask.

  • AsyncTasks идеально подходит для коротких операций (максимум на несколько секунд).
  • Асинхронная задача определяется тремя универсальными типами, называемыми Params, Progress и Result, и 4 шагами, называемыми onPreExecute() , doInBackground() , onProgressUpdate() и onPostExecute() .
  • В onPreExecute() вы можете определить код, который должен быть выполнен до начала фоновой обработки.
  • doInBackground имеет код, который необходимо выполнить в фоновом режиме, здесь, в doInBackground() мы можем отправить результаты несколько раз в поток событий методом publishProgress (), чтобы уведомить об обработке фона, мы можем просто вернуть результаты.
  • onProgressUpdate() получает обновления прогресса от doInBackground() , который публикуется методом publishProgress() , и этот метод может использовать это обновление для обновления потока событий
  • onPostExecute() обрабатывает результаты, возвращаемые методом doInBackground() .
  • Используемые общие типы
    • Парамс, тип параметров, отправленных в задачу при выполнении
    • Прогресс, тип единиц прогресса, опубликованных во время фоновых вычислений.
    • Результат, тип результата фонового вычисления.
  • Если задача async не использует какие-либо типы, тогда ее можно пометить как тип Void.
  • Запущенную задачу async можно отменить, вызвав метод cancel(boolean) .

Загрузка изображения с помощью Android AsyncTask

ваш макет .xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

<Button
    android:id="@+id/downloadButton"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Click Here to Download" />

<ImageView
    android:id="@+id/imageView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:contentDescription="Your image will appear here" />

</LinearLayout>

класс .java

package com.javatechig.droid;

import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class ImageDownladerActivity extends Activity {

    private ImageView downloadedImg;
    private ProgressDialog simpleWaitDialog;
    private String downloadUrl = "http://www.9ori.com/store/media/images/8ab579a656.jpg";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.asynch);
        Button imageDownloaderBtn = (Button) findViewById(R.id.downloadButton);

        downloadedImg = (ImageView) findViewById(R.id.imageView);

        imageDownloaderBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                new ImageDownloader().execute(downloadUrl);
            }

        });
    }

    private class ImageDownloader extends AsyncTask {

        @Override
        protected Bitmap doInBackground(String... param) {
            // TODO Auto-generated method stub
            return downloadBitmap(param[0]);
        }

        @Override
        protected void onPreExecute() {
            Log.i("Async-Example", "onPreExecute Called");
            simpleWaitDialog = ProgressDialog.show(ImageDownladerActivity.this,
                    "Wait", "Downloading Image");

        }

        @Override
        protected void onPostExecute(Bitmap result) {
            Log.i("Async-Example", "onPostExecute Called");
            downloadedImg.setImageBitmap(result);
            simpleWaitDialog.dismiss();

        }

        private Bitmap downloadBitmap(String url) {
            // initilize the default HTTP client object
            final DefaultHttpClient client = new DefaultHttpClient();

            //forming a HttpGet request 
            final HttpGet getRequest = new HttpGet(url);
            try {

                HttpResponse response = client.execute(getRequest);

                //check 200 OK for success
                final int statusCode = response.getStatusLine().getStatusCode();

                if (statusCode != HttpStatus.SC_OK) {
                    Log.w("ImageDownloader", "Error " + statusCode + 
                            " while retrieving bitmap from " + url);
                    return null;

                }

                final HttpEntity entity = response.getEntity();
                if (entity != null) {
                    InputStream inputStream = null;
                    try {
                        // getting contents from the stream 
                        inputStream = entity.getContent();

                        // decoding stream data back into image Bitmap that android understands
                        final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);

                        return bitmap;
                    } finally {
                        if (inputStream != null) {
                            inputStream.close();
                        }
                        entity.consumeContent();
                    }
                }
            } catch (Exception e) {
                // You Could provide a more explicit error message for IOException
                getRequest.abort();
                Log.e("ImageDownloader", "Something went wrong while" +
                        " retrieving bitmap from " + url + e.toString());
            } 

            return null;
        }
    }
}

Поскольку в настоящее время для примеров нет поля комментариев (или я его не нашел или у меня нет разрешения на это), вот несколько комментариев об этом:

Это хороший пример того, что можно сделать с помощью AsyncTask.

Однако в настоящее время в этом примере возникают проблемы с

  • возможные утечки памяти
  • приложение, если произошел поворот экрана незадолго до завершения асинхронной задачи.

Подробнее см .:

Передача активности как WeakReference во избежание утечек памяти

Для AsyncTask обычно требуется ссылка на вызвавшуюся активность.

Если AsyncTask является внутренним классом Activity, вы можете напрямую ссылаться на него и любые переменные / методы-члены.

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

В результате это приведет к утечке памяти.

Чтобы этого не произошло, используйте ссылку WeakReference в AsyncTask вместо прямой ссылки на Activity.

Вот пример AsyncTask, который использует WeakReference:

private class MyAsyncTask extends AsyncTask<String, Void, Void> {

    private WeakReference<Activity> mActivity;

    public MyAsyncTask(Activity activity) {
        mActivity = new WeakReference<Activity>(activity);
    }

    @Override
    protected void onPreExecute() {
        final Activity activity = mActivity.get();
        if (activity != null) {
            ....
        }
    }

    @Override
    protected Void doInBackground(String... params) {
        //Do something
        String param1 = params[0];
        String param2 = params[1];
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        final Activity activity = mActivity.get();
        if (activity != null) {
            activity.updateUI();
        }
    }
} 

Вызов AsyncTask из Activity:

new MyAsyncTask(this).execute("param1", "param2");

Вызов AsyncTask из фрагмента:

new MyAsyncTask(getActivity()).execute("param1", "param2");

Порядок исполнения

При первом вводе AsyncTasks выполнялись последовательно на одном фоновом потоке. Начиная с DONUT , это было изменено на пул потоков, позволяющий нескольким задачам работать параллельно. Начиная с HONEYCOMB , задачи выполняются в одном потоке, чтобы избежать ошибок обычного приложения, вызванных параллельным выполнением.

Если вы действительно хотите выполнить параллельное выполнение, вы можете вызвать executeOnExecutor(java.util.concurrent.Executor, Object[]) с помощью THREAD_POOL_EXECUTOR .

SERIAL_EXECUTOR -> Исполнитель, выполняющий задачи по очереди в последовательном порядке.

THREAD_POOL_EXECUTOR -> Исполнитель, который может использоваться для одновременного выполнения задач.

образец :

Task task = new Task();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
    task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, data);
else
    task.execute(data);

AsyncTask: последовательное выполнение и параллельное выполнение задачи

AsyncTask является абстрактным классом и не наследует класс Thread . Он имеет абстрактный метод doInBackground(Params... params) , который переопределяется для выполнения задачи. Этот метод вызывается из AsyncTask.call() .

Исполнитель является частью пакета java.util.concurrent .

Кроме того, AsyncTask содержит 2 Executor

THREAD_POOL_EXECUTOR

Он использует рабочие потоки для выполнения задач параллельно.

public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

SERIAL_EXECUTOR

Он выполняет задачу поочередно, то есть один за другим.

private static class SerialExecutor implements Executor { }

Оба Executor s является статическим, следовательно , только один THREAD_POOL_EXECUTOR и один SerialExecutor объекты существуют, но вы можете создать несколько AsyncTask объектов.

Поэтому, если вы попытаетесь выполнить несколько фоновых задач с помощью стандартного Executor ( SerialExecutor ), эта задача будет очереди и будет выполняться последовательно.

Если вы попытаетесь выполнить несколько фоновых задач с помощью THREAD_POOL_EXECUTOR , они будут выполняться параллельно.

Пример:

public class MainActivity extends Activity {
    private Button bt;
    private int CountTask = 0;
    private static final String TAG = "AsyncTaskExample";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bt = (Button) findViewById(R.id.button);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                BackgroundTask backgroundTask = new BackgroundTask ();
                Integer data[] = { ++CountTask, null, null };

                // Task Executed in thread pool ( 1 )
                backgroundTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, data);

                // Task executed Serially ( 2 )
                // Uncomment the below code and comment the above code of Thread
                // pool Executor and check
                // backgroundTask.execute(data);
                Log.d(TAG, "Task = " + (int) CountTask + " Task Queued");

            }
        });

    }

    private class BackgroundTask extends AsyncTask<Integer, Integer, Integer> {
        int taskNumber;

        @Override
        protected Integer doInBackground(Integer... integers) {
            taskNumber = integers[0];

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            Log.d(TAG, "Task = " + taskNumber + " Task Running in Background");

            publishProgress(taskNumber);
            return null;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected void onPostExecute(Integer aLong) {
            super.onPostExecute(aLong);
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            Log.d(TAG, "Task = " + (int) values[0]
                    + " Task Execution Completed");
        }
    }
}

Выполните несколько раз кнопку «Пуск», чтобы запустить задачу и увидеть результат.

Задача Выполняется в пуле потоков (1)

Для выполнения каждой задачи требуется 1000 мс.

При t = 36s задачи 2, 3 и 4 ставятся в очередь и начинают выполняться также потому, что они выполняются параллельно.

08-02 19:48:35.815: D/AsyncTaskExample(11693): Task = 1 Task Queued
08-02 19:48:35.815: D/AsyncTaskExample(11693): Task = 1 Task Running in Background
08-02 19:48:**36.025**: D/AsyncTaskExample(11693): Task = 2 Task Queued
08-02 19:48:**36.025**: D/AsyncTaskExample(11693): Task = 2 Task Running in Background
08-02 19:48:**36.165**: D/AsyncTaskExample(11693): Task = 3 Task Queued
08-02 19:48:**36.165**: D/AsyncTaskExample(11693): Task = 3 Task Running in Background
08-02 19:48:**36.325**: D/AsyncTaskExample(11693): Task = 4 Task Queued
08-02 19:48:**36.325**: D/AsyncTaskExample(11693): Task = 4 Task Running in Background
08-02 19:48:**36.815**: D/AsyncTaskExample(11693): Task = 1 Task Execution Completed
08-02 19:48:**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Queued
08-02 19:48:**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Running in Background
08-02 19:48:37.025: D/AsyncTaskExample(11693): Task = 2 Task Execution Completed
08-02 19:48:37.165: D/AsyncTaskExample(11693): Task = 3 Task Execution Completed
----------

Комментарий Task Executed in thread pool (1) и раскомментировании Task executed Serially (2).

Выполните несколько раз кнопку «Пуск», чтобы запустить задачу и увидеть результат.

Он выполняет задачу последовательно, поэтому каждая задача запускается после выполнения текущей задачи. Следовательно, когда выполнение задачи 1 завершается, в фоновом режиме запускается только Task 2. Наоборот.

08-02 19:42:57.505: D/AsyncTaskExample(10299): Task = 1 Task Queued
08-02 19:42:57.505: D/AsyncTaskExample(10299): Task = 1 Task Running in Background
08-02 19:42:57.675: D/AsyncTaskExample(10299): Task = 2 Task Queued
08-02 19:42:57.835: D/AsyncTaskExample(10299): Task = 3 Task Queued
08-02 19:42:58.005: D/AsyncTaskExample(10299): Task = 4 Task Queued
08-02 19:42:58.155: D/AsyncTaskExample(10299): Task = 5 Task Queued
08-02 19:42:58.505: D/AsyncTaskExample(10299): Task = 1 Task Execution Completed
08-02 19:42:58.505: D/AsyncTaskExample(10299): Task = 2 Task Running in Background
08-02 19:42:58.755: D/AsyncTaskExample(10299): Task = 6 Task Queued
08-02 19:42:59.295: D/AsyncTaskExample(10299): Task = 7 Task Queued
08-02 19:42:59.505: D/AsyncTaskExample(10299): Task = 2 Task Execution Completed
08-02 19:42:59.505: D/AsyncTaskExample(10299): Task = 3 Task Running in Background
08-02 19:43:00.035: D/AsyncTaskExample(10299): Task = 8 Task Queued
08-02 19:43:00.505: D/AsyncTaskExample(10299): Task = 3 Task Execution Completed
08-02 19:43:**00.505**: D/AsyncTaskExample(10299): Task = 4 Task Running in Background
08-02 19:43:**01.505**: D/AsyncTaskExample(10299): Task = 4 Task Execution Completed
08-02 19:43:**01.515**: D/AsyncTaskExample(10299): Task = 5 Task Running in Background
08-02 19:43:**02.515**: D/AsyncTaskExample(10299): Task = 5 Task Execution Completed
08-02 19:43:**02.515**: D/AsyncTaskExample(10299): Task = 6 Task Running in Background
08-02 19:43:**03.515**: D/AsyncTaskExample(10299): Task = 7 Task Running in Background
08-02 19:43:**03.515**: D/AsyncTaskExample(10299): Task = 6 Task Execution Completed
08-02 19:43:04.515: D/AsyncTaskExample(10299): Task = 8 Task Running in Background
08-02 19:43:**04.515**: D/AsyncTaskExample(10299): Task = 7 Task Execution Completed


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow