Android llamando a AsyncTask justo después de otro acabado

Tengo un problema con Android AsyncTask. Hay una actividad que contiene algo de TextView, un botón y una imagen. Cuando un usuario ingresa a esta actividad, inicio una asynctask para verificar si el usuario puede ir hacia la actividad (hasta que la tarea no finalice, el botón no está activo). Entonces quiero comenzar otra asyntask para obtener la imagen. Entonces hice una clase interna:

AsyncTask() authTask = new AsyncTask() { @Override protected JSONObject doInBackground(String... params) { //call the rest api } @Override protected void onPostExecute(JSONObject result) { // check the result // and make another asynctask AsyncTask imageTask = new Async.... { // get image } imageTask.execute(); } } 

y llamo authTask.execute(); desde el hilo de UI.

Tengo un mal presentimiento sobre esto, especialmente parece que no funciona (está bien algunas veces, pero de repente se “congela”: ninguna excepción se cuelga y la barra de progreso está girando. No pasa nada y el botón no estará activo). ¿Hay otra forma de obtener una información y cuando termina inmediatamente comienza otra tarea?

UDPATE: estoy trabajando con el nivel api 10. En authTask recibo información necesaria para iniciar imageTask (algunos id), así que tengo que llamar a estas tareas en una fila. En api nivel 10 es posible?

¡Gracias por adelantado!

Br, Peter

puede usar getStatus() verifica si AsyncTask está pendiente, ejecutándose o finalizándose. Y cuando inicia su nueva tarea, haga lo siguiente:

 if(authTask .getStatus() == AsyncTask.Status.PENDING){ // My AsyncTask has not started yet } if(authTask .getStatus() == AsyncTask.Status.RUNNING){ // My AsyncTask is currently doing work in doInBackground() } if(authTask .getStatus() == AsyncTask.Status.FINISHED){ // START NEW TASK HERE } 

ejemplo para tu aplicación:

 btn.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { if (authTask != null && authTask.getStatus() == AsyncTask.Status.FINISHED) { //START YOUR NEW TASK HERE } else { //IGNORE BUTTON CLICK } } }); 

1:

Puede escribir el código para authTask y luego para imageTask, uno después del otro, dentro de un solo doInBackground() . Esta única instancia de AsyncTask sería disparada por una sola instrucción execute() . Esto puede o no ser práctico dependiendo de las interacciones UI necesarias.


2:

Editar: como lo señala kabuku, esta información es principalmente para HoneyComb +. Pre HoneyComb Definitivamente iría con la opción 1 anterior. executeOnExecutor () es el nivel api 11+

En las versiones actualizadas, execute() enviará sus AsyncTasks en serie de forma predeterminada (ICS +). Si quiere asegurarse de que esto ocurra, especifique el ejecutor en serie.

En tu caso, esto sería:

 authTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); // Image task will only be done AFTER textViewTask is done imageTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); 

Y para versiones más nuevas, un simple

 ... // ICS+ and pre honeycomb (I think) authTask.execute(); // Image task will only be done AFTER textViewTask is done imageTask.execute(); ... 

De la documentación AsycnTask.execute ():

Nota: esta función progtwig la tarea en una cola para una única cadena de subprocesos o un grupo de subprocesos dependiendo de la versión de la plataforma. Cuando se introdujo por primera vez, las AsyncTasks se ejecutaron en serie en una única cadena de fondo. Comenzando con DONUT, esto se cambió a un conjunto de subprocesos que permite que varias tareas funcionen en paralelo. Después de HONEYCOMB, se planea volver a cambiar esto a un único hilo para evitar errores de aplicación comunes causados ​​por la ejecución en paralelo.


PD: Para ejecutar tareas independientes entre sí, debe usar AsyncTask.THREAD_POOL_EXECUTOR . Eso requiere un ejecutor diferente:

 // Go parallel! (NOT what you want) task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 

No es un buen diseño para anidar AsyncTask. Haga todo el trabajo pesado en doInBackground y simplemente publique / actualice los resultados. En otras palabras, combine el procesamiento de la segunda AsyncTask en la primera.

Del código que mostraste no parece tener sentido generar una segunda tarea. Solo obtenga su imagen dentro de doInBackground de la primera tarea inmediatamente después de la autorización. Si necesita actualizar la IU en el medio, puede hacerlo en la actualización de progreso.

 int count; private void attemptConnect() { count = 0; str_lang = "English"; str_wait = "Plaese Wait"; new AllQuestion().execute(); } private class AllQuestion extends AsyncTask { ProgressDialog pg; @Override protected void onPreExecute() { super.onPreExecute(); pg = new ProgressDialog(LanguageActivity.this); pg.setProgressStyle(ProgressDialog.STYLE_SPINNER); pg.setMessage(str_wait); pg.setCancelable(false); pg.show(); } @Override protected String doInBackground(String... strings) { try { SoapObject soapObject = new SoapObject(AppConstant.NAMESPACE, AppConstant.QUESTION_SOAP_METHOD); soapObject.addProperty("language", str_lang); SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.dotNet = true; envelope.setOutputSoapObject(soapObject); HttpTransportSE se = new HttpTransportSE(AppConstant.webUrl); se.call(AppConstant.QUESTION_SOAP_ACTION, envelope); Object responce = envelope.getResponse(); Log.d("Question List:=>>", "" + responce); return responce.toString(); } catch (Exception e) { e.printStackTrace(); pg.dismiss(); return null; } } @Override protected void onPostExecute(String s) { super.onPostExecute(s); if (pg.isShowing()) { pg.dismiss(); Log.i(TAG, s); if (s != null || !s.equalsIgnoreCase("")) { try { JSONArray array = new JSONArray(s); for (int i = 0; i < array.length(); i++) { JSONObject obj = array.getJSONObject(i); String queId = obj.getString(TAG_QID); String que = obj.getString(TAG_QUE); String str_Opt = obj.getString(TAG_OPT); question = new Question(queId, que, str_lang, str_catId, str_Opt, manager.getDateTime()); helper.insertQuestion(question); } count++; if (count < 5) { if (count == 1) { str_lang = "German"; str_wait = "bitte warte einen Moment"; new AllQuestion().execute(); } if (count == 2) { str_lang = "Italian"; str_wait = "per favore aspetta un momento"; new AllQuestion().execute(); } if (count == 3) { str_lang = "Chinese"; str_wait = "请稍候"; new AllQuestion().execute(); } if (count == 4) { str_lang = "French"; str_wait = "patientez s'il-vous-plait"; new AllQuestion().execute(); } Log.d("All Question:-", question.toString()); } catch (JSONException e) { e.printStackTrace(); } } } } } 

Tengo una idea para hacer series asíncronas en una sola tarea asíncrona :

 protected Boolean doInBackground(String... params) { if(params[0] == "taskA") { //do somthing params[0] = "taskB"; } if(params[0] == "taskB") { //do somthing params[0] = "taskC"; } if(params[0] == "taskC") { //do somthing params[0] = "taskD"; } if(params[0] == "taskD") { //do somthing return true; } 

Y en su hilo principal simplemente llame a la tarea asincrónica de esta manera:

 ShowMyProgress(); //if you like new MyAsyncTask().execute("taskA"); 

Y finalmente puedes ocultar tu progreso en onPostExecute como:

 protected void onPostExecute(final Boolean success) { if (success) { .... HideMyProgress(); } } 

He resuelto este tipo de problema cuando tuve que descargar algo de una base de datos antes de iniciar sesión en el usuario en la aplicación, con esto solucioné este problema.

Para usar ObservableInteger puedes hacer esto

primero declararlo

 private ObservableInteger mObsInt; 

luego, en su onCreate tendrá un oyente esperando que cambien los valores de mObsInt, luego de que esos valores cambien puede hacer lo que quiera

 //Listener mObsInt = new ObservableInteger(); mObsInt.set(0); mObsInt.setOnIntegerChangeListener(new OnIntegerChangeListener() { @Override public void onIntegerChanged(int newValue) { if (mObsInt.get()==1) //Do something if the first asyncTask finishes if (mObsInt.get()==2){ //Do something if the second asyncTask finishes, in this case i just go to another activity when both asyncTasks finish Intent mainIntent = new Intent().setClass(LoginActivity.this, Principal.class); startActivity(mainIntent); finish(); } } }); 

Entonces, cómo funciona

ObservableInteger buscará cambios en la variable mObsInt , entonces digamos que si mObsInt es igual a 1, hará algo, si es igual a 2 hará otra cosa, entonces, resolver este problema con 2 asynctasks es fácil, cuando uno de las asynctasks terminan mObsInt será igual a 1, si la otra asyncTask termina así que mObsInt será mObsInt++ , y luego su mObsInt será igual a 2, el oyente estará esperando los valores, y luego hará lo que quiera cuando el los valores coinciden con su statement if en el método onCreate

ahora, solo en sus tareas asíncronas, simplemente coloque en su método onPostExecute () esta línea

 mObsInt.set(mObsInt.get()+1); 

entonces si el primer final asíncrono, mObsint == 1, si el segundo termina mObsInt == 2, y luego maneja lo que quiere hacer en su método onCreate

Espero que esto te ayude, me ayudó

Puede obtener más información en este documento: https://developer.android.com/reference/android/databinding/ObservableInt.html

feliz encoding!