Android
AsyncTask
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 queonPreExecute()
termine de ejecutarse. -
onProgressUpdate()
: se invoca en el subproceso de la interfaz de usuario después de una llamada apublishProgress(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()
yonPostExecute()
. - 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étodoonProgressUpdate()
recibe actualizaciones de progreso del métododoInBackground()
, que se publica a través del métodopublishProgress()
, y este método puede usar esta actualización de progreso para actualizar el hilo de eventos -
onPostExecute()
métodoonPostExecute()
maneja los resultados devueltos por el métododoInBackground()
. - 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
- http://stackoverflow.com/documentation/android/117/asynctask/5377/possible-problems-with-inner-async-tasks
- Evite las actividades con fugas con AsyncTask
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