Buscar..


Parámetros

Parámetro Detalles
Parámetros el tipo de los parámetros enviados a la tarea en la ejecución.
Progreso El tipo de unidades de progreso publicadas durante el cómputo de fondo.
Resultado El tipo del resultado del cálculo de fondo.

Uso básico

En Actividades y servicios de Android, la mayoría de las devoluciones de llamada se ejecutan en el hilo principal . Esto facilita la actualización de la interfaz de usuario, pero la ejecución de tareas pesadas de procesador o de E / S en el subproceso principal puede hacer que su interfaz de usuario se detenga y deje de responder ( documentación oficial sobre lo que sucede).

Puedes remediar esto poniendo estas tareas más pesadas en un hilo de fondo.

Una forma de hacerlo es usar una AsyncTask , que proporciona un marco para facilitar el uso de un subproceso en segundo plano, y también realizar tareas de subprocesos en la interfaz de usuario antes, durante y después de que el subproceso en segundo plano haya completado su trabajo.

Métodos que se pueden anular al extender AsyncTask :

  • onPreExecute() : invocado en el subproceso de la interfaz de usuario antes de que se ejecute la tarea
  • doInBackground() : se invoca en el subproceso en segundo plano inmediatamente después de que onPreExecute() termine de ejecutarse.
  • onProgressUpdate() : se invoca en el subproceso de la interfaz de usuario después de una llamada a publishProgress(Progress...) .
  • onPostExecute() : invocado en el subproceso de la interfaz de usuario después de que finalice el cálculo en segundo plano

Ejemplo

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.");
        }
    }

}

Uso:

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

o simplemente:

new MyCustomAsyncTask().execute(userSuppliedFilename);

Nota

Al definir una AsyncTask podemos pasar tres tipos entre corchetes < > .
Definido como <Params, Progress, Result> Parámetros <Params, Progress, Result> (vea la sección Parámetros )

En el ejemplo anterior, hemos utilizado los tipos <File, Void, String> :

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

Void se utiliza cuando desea marcar un tipo como no utilizado.

Tenga en cuenta que no puede pasar tipos primitivos (es decir, int , float y otros 6) como parámetros. En tales casos, debe pasar sus clases de envoltorio , por ejemplo, Integer lugar de int , o Float lugar de float .

El ciclo de vida de AsyncTask y Activity

AsyncTasks no sigue el ciclo de vida de las instancias de la actividad. Si inicia una AsyncTask dentro de una actividad y gira el dispositivo, la actividad se destruirá y se creará una nueva instancia. Pero la AsyncTask no morirá. Seguirá viviendo hasta que se complete.

Solución: AsyncTaskLoader

Una subclase de cargadores es el AsyncTaskLoader. Esta clase realiza la misma función que AsyncTask, pero mucho mejor. Puede manejar los cambios de configuración de la actividad más fácilmente, y se comporta dentro de los ciclos de vida de Fragmentos y Actividades. Lo bueno es que AsyncTaskLoader se puede usar en cualquier situación en la que se esté utilizando AsyncTask. En cualquier momento, los datos deben cargarse en la memoria para que la Actividad / Fragmento los maneje, AsyncTaskLoader puede hacer el trabajo mejor.

Cancelando AsyncTask

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

Esto no detiene su tarea si estaba en progreso, solo establece el indicador cancelado que puede verificarse verificando el valor de retorno de isCancelled() (asumiendo que su código se está ejecutando actualmente) haciendo esto:

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

Nota

Si una AsyncTask se cancela mientras doInBackground(Params... params) aún se está ejecutando, el método onPostExecute(Result result) NO se llamará después de que doInBackground(Params... params) . AsyncTask llamará a onCancelled(Result result) para indicar que la tarea se canceló durante la ejecución.

Progreso de publicación

A veces, necesitamos actualizar el progreso del cálculo realizado por una AsyncTask . Este progreso podría representarse por una cadena, un entero, etc. Para hacer esto, tenemos que usar dos funciones. Primero, debemos configurar la función onProgressUpdate cuyo tipo de parámetro sea el mismo que el segundo parámetro de tipo de nuestra AsyncTask .

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

Segundo, tenemos que usar la función publishProgress necesariamente en la función doInBackground , y eso es todo, el método anterior hará todo el trabajo.

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

Descarga la imagen usando AsyncTask en Android

Este tutorial explica cómo descargar la imagen usando AsyncTask en Android. El siguiente ejemplo descarga la imagen mientras muestra la barra de progreso mientras se descarga.

Entendiendo Android AsyncTask

La tarea asíncrona le permite implementar MultiThreading sin ensuciarse las manos en hilos. AsyncTask permite el uso correcto y fácil del hilo de la interfaz de usuario. Permite realizar operaciones en segundo plano y pasar los resultados en el subproceso de la interfaz de usuario. Si está haciendo algo aislado relacionado con la IU, por ejemplo, descargando datos para presentarlos en una lista, siga adelante y use AsyncTask.

  • Las AsyncTasks deberían usarse idealmente para operaciones cortas (unos segundos como máximo).
  • Una tarea asíncrona se define mediante 3 tipos genéricos, llamados Parámetros, Progreso y Resultado, y 4 pasos, llamados onPreExecute() , doInBackground() , onProgressUpdate() y onPostExecute() .
  • En onPreExecute() puede definir el código, que debe ejecutarse antes de que comience el procesamiento en segundo plano.
  • doInBackground tiene un código que debe ejecutarse en segundo plano, aquí en doInBackground() podemos enviar resultados varias veces al hilo de eventos mediante el método publishProgress (), para notificar que se ha completado el procesamiento en segundo plano, podemos devolver los resultados de manera simple.
  • onProgressUpdate() método onProgressUpdate() recibe actualizaciones de progreso del método doInBackground() , que se publica a través del método publishProgress() , y este método puede usar esta actualización de progreso para actualizar el hilo de eventos
  • onPostExecute() método onPostExecute() maneja los resultados devueltos por el método doInBackground() .
  • Los tipos genéricos utilizados son
    • Parámetros, el tipo de los parámetros enviados a la tarea en la ejecución
    • Progreso, el tipo de las unidades de progreso publicadas durante el cálculo de fondo.
    • Resultado, el tipo de resultado del cálculo de fondo.
  • Si una tarea asíncrona no utiliza ningún tipo, puede marcarse como Tipo de vacío.
  • Una tarea asíncrona en ejecución puede cancelarse llamando al método de cancel(boolean) .

Descarga de imágenes usando Android AsyncTask

su diseño .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>

clase .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;
        }
    }
}

Como actualmente no hay un campo de comentarios para los ejemplos (o no lo he encontrado o no tengo permiso para ello), aquí hay algunos comentarios al respecto:

Este es un buen ejemplo de lo que se puede hacer con AsyncTask.

Sin embargo, el ejemplo actualmente tiene problemas con

  • posibles fugas de memoria
  • La aplicación se bloquea si se produce una rotación de pantalla poco antes de que finalice la tarea asíncrona.

Para más detalles ver:

Pase la actividad como WeakReference para evitar pérdidas de memoria

Es común que una AsyncTask requiera una referencia a la Actividad que la llamó.

Si la AsyncTask es una clase interna de la Actividad, puede hacer referencia a ella y a cualquier variable / método miembro directamente.

Sin embargo, si la AsyncTask no es una clase interna de la Actividad, deberá pasar una referencia de la Actividad a la AsyncTask. Cuando haga esto, un problema potencial que puede surgir es que AsyncTask mantendrá la referencia de la Actividad hasta que AsyncTask haya completado su trabajo en su hilo de fondo. Si la Actividad finaliza o se cancela antes de que se realice el trabajo de subproceso de fondo de AsyncTask, la AsyncTask seguirá teniendo su referencia a la Actividad y, por lo tanto, no se puede recolectar la basura.

Como resultado, esto causará una pérdida de memoria.

Para evitar que esto suceda, use una WeakReference en la AsyncTask en lugar de tener una referencia directa a la Actividad.

Aquí hay un ejemplo de AsyncTask que utiliza una 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();
        }
    }
} 

Llamando a la AsyncTask desde una actividad:

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

Llamando a la AsyncTask desde un Fragmento:

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

Orden de ejecución

Cuando se introdujo por primera vez, las AsyncTasks se ejecutaron en serie en un solo hilo de fondo. Comenzando con DONUT , esto se cambió a un grupo de subprocesos permitiendo que múltiples tareas funcionen en paralelo. A partir de HONEYCOMB , las tareas se ejecutan en un solo hilo para evitar errores comunes de aplicación causados ​​por la ejecución paralela.

Si realmente desea una ejecución paralela, puede invocar executeOnExecutor(java.util.concurrent.Executor, Object[]) con THREAD_POOL_EXECUTOR .

SERIAL_EXECUTOR -> Un Ejecutor que ejecuta las tareas de una en una en orden serial.

THREAD_POOL_EXECUTOR -> Un Executor que se puede utilizar para ejecutar tareas en paralelo.

muestra:

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

AsyncTask: Ejecución en serie y ejecución paralela de tareas

AsyncTask es una clase abstracta y no hereda la clase Thread . Tiene un método abstracto doInBackground(Params... params) , que se reemplaza para realizar la tarea. Este método se llama desde AsyncTask.call() .

El ejecutor es parte del paquete java.util.concurrent .

Por otra parte, AsyncTask contiene 2 Executor s

THREAD_POOL_EXECUTOR

Utiliza hilos de trabajo para ejecutar las tareas en paralelo.

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

SERIAL_EXECUTOR

Ejecuta la tarea en serie, es decir, uno por uno.

private static class SerialExecutor implements Executor { }

Los dos Executor son estáticos , por lo tanto, solo THREAD_POOL_EXECUTOR un objeto THREAD_POOL_EXECUTOR y un objeto SerialExecutor , pero puede crear varios objetos AsyncTask .

Por lo tanto, si intenta realizar varias tareas en segundo plano con el Ejecutor predeterminado ( SerialExecutor ), estas tareas se pondrán en cola y se ejecutarán en serie.

Si intenta realizar varias tareas en segundo plano con THREAD_POOL_EXECUTOR , entonces se ejecutarán en paralelo.

Ejemplo:

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");
        }
    }
}

Haga clic en el botón varias veces para iniciar una tarea y ver el resultado.

Tarea ejecutada en grupo de subprocesos (1)

Cada tarea tarda 1000 ms en completarse.

En t = 36s, las tareas 2, 3 y 4 se ponen en cola y comienzan a ejecutarse también porque se ejecutan en paralelo.

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

La Task Executed in thread pool comentario se Task Executed in thread pool (1) y la Task executed Serially descomentar se Task executed Serially (2).

Haga clic en el botón varias veces para iniciar una tarea y ver el resultado.

Está ejecutando la tarea en serie, por lo que cada tarea se inicia después de que la tarea actual se haya completado. Por lo tanto, cuando se completa la ejecución de la Tarea 1, solo la Tarea 2 comienza a ejecutarse en segundo plano. Viceversa.

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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow