una tutorial tiempo thread termine tareas tarea studio que programacion peticiones hilos esperar ejemplo ejecutar cierto cada asynctask asincronos asincronas android android-asynctask

tutorial - tareas asincronas android



Tarea asíncrona de Android (2)

Esto fue preguntado en una de las entrevistas de Android. Me preguntaron si es posible iniciar otra tarea asíncrona (deje que sea Tarea2) desde el método doInBackground () de la tarea asíncrona 1 (sea Tarea1). He pasado por los documentos que dicen lo siguiente:

La instancia de tarea debe crearse en el subproceso de la interfaz de usuario.

execute (Params ...) debe invocarse en el subproceso de la interfaz de usuario.

Según estas afirmaciones, creo que no debería ser posible iniciar una tarea desde el método en segundo plano de otra tarea. Además, la tarea asíncrona tiene métodos de UI (que no se pueden usar en un hilo de fondo), por lo que fortaleció mi argumento y respondí que no era posible.

Al verificar una aplicación de demostración simple, vi que sí es posible hacerlo. Algún código de demostración:

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; init(); Log.v ("gaurav", "Thread is : " + Thread.currentThread().getName()); Task1 task = new Task1(); task.execute(); } class Task1 extends AsyncTask { @Override protected Object doInBackground(Object... params) { // TODO Auto-generated method stub Log.v ("gaurav", "Thread task 1 is : " + Thread.currentThread().getName()); Task2 task = new Task2(); task.execute(); return null; } } class Task2 extends AsyncTask { @Override protected Object doInBackground(Object... params) { // TODO Auto-generated method stub Log.v ("gaurav", "Thread task 2 is : " + Thread.currentThread().getName()); Log.v ("gaurav", "Task 2 started"); return null; } }

Obtengo los siguientes registros que indican la ejecución exitosa:

> 08-07 09:46:25.564: V/gaurav(2100): Thread is : main 08-07 > 09:46:25.564: V/gaurav(2100): Thread task 1 is : AsyncTask #3 08-07 > 09:46:25.564: V/gaurav(2100): Thread task 2 is : AsyncTask #4 08-07 > 09:46:25.564: V/gaurav(2100): Task 2 started

He comprobado esto en el dispositivo ICS, KK y L y funciona bien para todos.

Una razón por la que podría pensar es que no estoy anulando ningún método de UI y haciendo ninguna actualización de UI en mi segunda tarea, por lo que no causa ningún problema, pero no estoy seguro. Incluso si ese es el caso, viola las reglas de subprocesos mencionadas en la guía del desarrollador.

Como referencia, también verifiqué este enlace: inicie AsyncTask desde otro AsyncTask doInBackground () pero la respuesta indica que se inicie la segunda tarea utilizando el método runOnUiThread () dentro de doInBackground (). Me gustaría algo de ayuda sobre lo que está pasando aquí. Gracias.


Cambiemos tu código a lo siguiente:

class Task1 extends AsyncTask { @Override protected Object doInBackground(Object... params) { // TODO Auto-generated method stub Log.v ("gaurav", "Thread task 1 is : " + Thread.currentThread().getName()); Task2 task = new Task2(); task.execute(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Log.v ("gaurav", "Log after sleeping"); return null; } } class Task2 extends AsyncTask { @Override protected Object doInBackground(Object... params) { // TODO Auto-generated method stub Log.v ("gaurav", "Thread task 2 is : " + Thread.currentThread().getName()); Log.v ("gaurav", "Task 2 Started"); return null; } }

Ahora el LogCat devuelve:

08-07 06:13:44.208 3073-3073/testapplication V/gaurav﹕ Thread is : main 08-07 06:13:44.209 3073-3091/testapplication V/gaurav﹕ Thread task 1 is : AsyncTask #1 08-07 06:13:49.211 3073-3091/testapplication V/gaurav﹕ Log after sleeping 08-07 06:13:49.213 3073-3095/testapplication V/gaurav﹕ Thread task 2 is : AsyncTask #2 08-07 06:13:49.213 3073-3095/testapplication V/gaurav﹕ Task 2 Started

Como puede ver, la Task 2 se ejecuta después del final de la ejecución de la Task 1 (incluso después de dormir durante 5 segundos). Esto significa que la segunda tarea no se iniciará hasta que se complete la primera.

¿Por qué? La razón está detrás del código fuente de AsyncTask . Por favor considere el método de execute() :

public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } }

y el método scheduleNext() :

protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } }

La palabra clave más importante en estos métodos está synchronized que garantiza que estos métodos se ejecutarán solo en un subproceso al mismo tiempo. Cuando llama al método de execute , ofrece un nuevo Runnable to mTask que es una instancia de la ArrayDeque<Runnable> que funciona como un serializador de las diferentes solicitudes en diferentes subprocesos [más información] . Si no hubiera Runnable ejecutado (es decir, if (mActive == null) ), se llamaría a scheduleNext() , de lo contrario, se llamaría a scheduleNext() en el bloque finally después del final (por cualquier motivo) del final ejecutable de Runnable . Todos los Runnable s se ejecutan en un hilo separado por THREAD_POOL_EXECUTOR .

¿Qué hay de malo en la ejecución de AsyncTask desde otros hilos? Comenzando con Jelly Bean, un AsyncTask se carga en clase al inicio de la aplicación en el subproceso de la interfaz de usuario, por lo que se garantiza que las devoluciones de llamada se produzcan en el subproceso de la interfaz de usuario, sin embargo, antes de la versión de Jelly Bean, si otro hilo crea el AsyncTask las devoluciones de llamada No se produce en el hilo correcto.

Por lo tanto, AsyncTask implementaciones de AsyncTask deben llamarse desde el subproceso de la interfaz de usuario solo en plataformas anteriores a Jelly Bean ( + y + ).

Aclaración: tenga en cuenta el siguiente ejemplo que simplemente aclara las diferencias entre las diferentes versiones de plataforma de Android:

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); new Thread() { @Override public void run() { Task1 task = new Task1(); task.execute(); } }.start(); } class Task1 extends AsyncTask { @Override protected Object doInBackground(Object... params) { return null; } }

Funciona bien en Android 5.1, pero se bloquea con la siguiente excepción en Android 2.3:

08-07 12:05:20.736 584-591/github.yaa110.testapplication E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-8 java.lang.ExceptionInInitializerError at github.yaa110.testapplication.Main2Activity$1.run(Main2Activity.java:21) Caused by: java.lang.RuntimeException: Can''t create handler inside thread that has not called Looper.prepare() at android.os.Handler.<init>(Handler.java:121) at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421) at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421) at android.os.AsyncTask.<clinit>(AsyncTask.java:152)             at github.yaa110.testapplication.Main2Activity$1.run(Main2Activity.java:21)


public class MainActivity extends Activity { private final static String TAG = "ThreadingAsyncTask"; private ImageView mImageView; private ProgressBar mProgressBar; private int mDelay = 500; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mImageView = (ImageView) findViewById(R.id.imageView);; mProgressBar = (ProgressBar) findViewById(R.id.progressBar); final Button button = (Button) findViewById(R.id.loadButton); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { new LoadIconTask().execute(R.drawable.cheetah); } }); final Button otherButton = (Button) findViewById(R.id.otherButton); otherButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "I''m Working", Toast.LENGTH_SHORT).show(); } }); } class LoadIconTask extends AsyncTask<Integer, Integer, Bitmap> { @Override protected void onPreExecute() { mProgressBar.setVisibility(ProgressBar.VISIBLE); } @Override protected Bitmap doInBackground(Integer... resId) { Bitmap tmp = BitmapFactory.decodeResource(getResources(), resId[0]); // simulating long-running operation for (int i = 1; i < 11; i++) { sleep(); publishProgress(i * 10); } return tmp; } @Override protected void onProgressUpdate(Integer... values) { mProgressBar.setProgress(values[0]); } @Override protected void onPostExecute(Bitmap result) { mProgressBar.setVisibility(ProgressBar.INVISIBLE); mImageView.setImageBitmap(result); } private void sleep() { try { Thread.sleep(mDelay); } catch (InterruptedException e) { Log.e(TAG, e.toString()); } } } }