Devolver datos de AsyncTask Android

Traté de referir la misma pregunta en SO, pero no recibió ayuda.

En mi aplicación para Android, estoy planeando implementar cotización reciente que el usuario ha visitado, es decir, similar a las páginas visitadas recientemente en la web.

Los siguientes son los pasos que estoy siguiendo:

1.) Siempre que el usuario abra cualquier vista de empresa, obtenga los símbolos de la empresa de la base de datos

2.) A continuación, almacene el símbolo actual junto con dateTime en la base de datos.

3.) Para todos los símbolos obtenidos de la base de datos, Buscar su current value y %Change y mostrar Nombre de la empresa, valor actual y% Cambio en una lista.

El problema surge en la clase ASyncTask como método postExecute no permite que su tipo de retorno sea diferente de void .

¿Estoy haciendo algo mal?

Cualquier ayuda será salvavidas!

 String[] rsym,rcmp,rchg; rdbM = new RecentDBManager(CompanyView.this); try { Calendar date1 = Calendar.getInstance(); SimpleDateFormat dateformatter = new SimpleDateFormat( "dd/MM/yyyy HH:mm:ss"); String currentdate = dateformatter.format(date1.getTime()); rdbM.openDB(); //STEP 1 rsym = rdbM.getRecent_sym(); //STEP 2 rdbM.setData(currentsymbol, currentdate); rdbM.closeDB(); } catch (Exception e) { throw new Error(" *** ERROR in DB Access *** "+ e.toString()); } //STEP 3 for(int i=0;i<rsym.length;i++) { DownloadRecentQuote quotetask = new DownloadRecentQuote(); recentquotetask .execute(new String[] { "http://abc.com/stockquote.aspx?id=" + rsym[i] }); //CURRENT VALUE and %CHANGE which should be returned from ASyncTask class rcmp[i]=valuearr[0]; rchg[i]=valuearr[1]; } list1 = new ArrayList<HashMap<String, String>>(); HashMap<String, String> addList1; for (int i = 0; i < limit; i++) { addList1 = new HashMap<String, String>(); addList1.put(RecentSym_COLUMN, rsym[i]); addList1.put(RecentCMP_COLUMN, rcmp[i]); addList1.put(RecentChg_COLUMN, rchg[i]); list1.add(addList1); RecentAdapter adapter1 = new RecentAdapter( CompanyView.this, CompanyView.this, list1); listrecent.setAdapter(adapter1); } private class DownloadRecentQuote extends AsyncTask<String, Void, String> { /* Fetching data for RecentQuote information */ @Override protected String doInBackground(String... urls) { String response = ""; for (String url : urls) { DefaultHttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(url); try { HttpResponse execute = client.execute(httpGet); InputStream content = execute.getEntity().getContent(); BufferedReader buffer = new BufferedReader( new InputStreamReader(content)); String s = ""; while ((s = buffer.readLine()) != null) { response += s; } } catch (Exception e) { e.printStackTrace(); } } return response; } @Override protected void onPostExecute(String result) { arr1 = result.split("@"); if (arr1[0].length() != 0) { if (arr1[0].equals("1")) { arr = arr1[1].split(";"); //RETURN 2 STRINGS String valuearr[]; valuearr[0] = arr[3]; valuearr[1] = arr[6].concat("%"); //return valuearr; } } } 

PostExecute () no puede devolver un valor, ¿por qué o hacia qué? Su método original que invocó el AsyncTask se ha ido porque su AsyncTask se está ejecutando en el fondo. Es un significado asincrónico cuando AsyncTask.execute () devuelve que todavía se está ejecutando en segundo plano, y por lo tanto postExecute () no puede devolver un valor porque no hay nada para devolverlo.

En su lugar, su AsyncTask necesita una referencia de nuevo a su actividad o algún otro objeto para que pueda publicar sus valores de nuevo a ella. En su código las líneas después de llamar a execute () no pueden estar allí porque su tarea no ha terminado. En su lugar, debe crear un método denominado updateSymbol (currentPrice, percentChange), mover todo ese código debajo de execute (), y en su AsyncTask debe pasar una referencia a la Activity. A continuación, llame a updateSymbol (currentPrice, percentChange) del método onPostExecute ().

Pero, tenga cuidado si tiene una referencia a una actividad que puede ser destruida mientras su doInBackground () se está ejecutando, y cuando postExecute () se ejecuta sólo debe dejar caer los resultados o no intentar actualizar la interfaz de usuario. Por ejemplo, el usuario gira su teléfono causando que la actividad sea destruida. Creo que es mejor mantener una referencia a AsyncTask en la actividad por lo que puede cancelar () si la actividad se destruye. Puede llamar a AsyncTask.cancel () y luego verificar si su tarea se canceló como:

 public void postExecute( String result ) { if( !isCanceled() ) { // do your updating here activity.setSymbol( result ); } } 

Es muy fácil crear una clase base para todas las actividades para que pueda realizar un seguimiento de AsyncTasks en ejecución:

 public class BaseActivity extends Activity { List<AsyncTask> runningTasks; public void onStop() { for( AsyncTask task : runningTasks ) { task.cancel(true); } } public AsyncTask start( AsyncTask task ) { runningTasks.add( task ); return task; } public void done( AsyncTask task ) { runningTasks.remove( task ); } } 

Algunos punteros rápidos. No es necesario ejecutar (new String [] {"blah" + blah}). Varargs en Java le permiten hacer esto. Ejecutar ("bla" + bla). Usted también está cogiendo excepciones y continuando sin realmente manejarlas. Será difícil cuando algo realmente sucede porque su aplicación los atrapa, y simplemente continúa como si nada hubiera pasado. Si recibe un error, es posible que desee proporcionar algunos comentarios al usuario y dejar de intentar ejecutar ese proceso. Detener, mostrar un error al usuario, y dejar que hagan lo siguiente. Mueva los bloques de captura a la parte inferior de los métodos.

Esencialmente, AsyncTask.onPostExecute () es donde se hace lo que se quiera hacer después de ejecutar DoInBackground () de AsyncTask y se devuelve el resultado de la ejecución. Esto debe considerarse la mejor práctica.

Cuando se llama a AsyncTask (). Execute () desde el subproceso de UI (nota que este método debe llamarse desde el subproceso de UI), el framework de Android crea un subproceso de trabajo y comienza a ejecutar lo que escribió en AsyncTask.doInBackground () en este trabajador hilo. En este punto (después de llamar a AsyncTask (). Execute ()), el subproceso de interfaz de usuario continúa ejecutando código después de nuevo AsyncTask (). Execute (). Así que ahora durante el tiempo de ejecución, tiene dos subprocesos (interfaz de usuario y subproceso de trabajo) que se ejecutan simultáneamente.

¿Pero dónde y cuándo se devuelve el resultado de la ejecución de AsyncTask del hilo de trabajo al subproceso de UI?

El punto donde su hilo de trabajo (doInBackground ()) termina y devuelve al subproceso de UI es AysncTask.onPostExecute (). Este método está garantizado para ser llamado por el marco en el hilo de interfaz de usuario tan pronto como AsyncTask termina. En otras palabras, no nos importa dónde y cuando AsyncTask.onPostExecute () se llama en tiempo de ejecución, sólo tenemos que garantizar que se llamará en última instancia en algún momento en el futuro. Esta es la razón por la que este método no devuelve un resultado de ejecución, sino que requiere que el resultado de la ejecución se pase como el único parámetro del método de doInBackground ().

Además, la API de Android proporciona una forma de devolver un resultado de ejecución AsyncTask en el tiempo de codificación, AsyncTask.get () :

 MyAsyncTask myAsyncTask = new MyAsyncTask(); // This must be called from the UI thread: myAsyncTask.execute(); // Calling this will block UI thread execution: ExecutionResult result = myAsyncTask.get(); 

Tenga en cuenta que AsyncTask.get () bloqueará la ejecución del subproceso de llamada y probablemente obtendrá una excepción ANR si lo llama en el subproceso de UI. Esta es la carga útil de usar AsyncTask.get (), llamándolo en el subproceso de UI, está haciendo que su AsyncTask (subproceso de trabajo) se ejecute de forma síncrona con el subproceso de UI (haciendo que la interfaz de usuario quede en espera). Para resumir, esto es factible pero no recomendado.

Sólo para referencia futura, porque este post es un poco viejo:

He creado una clase de actividad que tiene un método onStart () y una clase separada para el AsyncTask. Basado en mi prueba, después del método doInbackground () el resultado será enviado a la actividad primero y después de que onPostExecute () se ejecutará. Esto se debe a que basado en logcat, tengo mis primeros datos de respuesta (enviados por el servidor) primero, entonces esta respuesta se mostrará de nuevo de la actividad y el último el mensaje en onPostExecute () se mostrará.

Código de la actividad:

 @Override protected void onStart() { super.onStart(); String str = "***"; if(isConnectedToInternet()){ myAsyncTask.execute(); try { if(myAsyncTask.get()) str = myAsyncTask.getResponseMsg(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } catch (CancellationException e) { e.printStackTrace(); } } Log.i("Data returned by server2:", str); } 

Código AsyncTask:

 public class MyAsyncTask extends AsyncTask<Void, Void, Boolean> { private URL url; private HttpURLConnection conn; private String strResponseMsg; public MyAsyncTask(String url) throws MalformedURLException{ this.url = new URL(url); } @Override protected void onPreExecute() { Log.i("Inside AsyncTask", "myAsyncTask is abut to start..."); } @Override protected Boolean doInBackground(Void... params) { boolean status = false; try { conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(Manager.ConnTimeout); conn.setReadTimeout(Manager.ReadTimeout); int responseCode = conn.getResponseCode(); Log.i("Connection oppened", "Response code is:" + responseCode); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); if (in != null) { StringBuilder strBuilder = new StringBuilder(); // Read character by character int ch = 0; while ((ch = in.read()) != -1) strBuilder.append((char) ch); // Showing returned message strResponseMsg = strBuilder.toString(); Log.i("Data returned by server:", strResponseMsg); status = true; } in.close(); } } catch (IOException e) { e.printStackTrace(); } return status; } @Override protected void onPostExecute(Boolean result) { Log.i("Inside AsyncTask", "myAsyncTask finished its task. Returning data to caller..."); } public String getResponseMsg(){ return strResponseMsg; } } 
  • Idioma para cerrar un cursor
  • ¿Cómo actualizo mi ListView después de los cambios en la base de datos?
  • ¿Cómo usar SQLite de Servicios en Android?
  • Cómo lograr una relación de "herencia" en la base de datos SQLite en Android
  • Unir tablas en android
  • Android sqlLite ON CONFLICT IGNORE se ignora en ICS
  • Lectura de datos de 4 archivos CSV estáticos en Android: Best Approach?
  • Excepción de SQLite "no such table" de Android
  • Cómo implementar SQLCipher cuando se utiliza SQLiteOpenHelper
  • ¿Cómo comunicarse entre WebView y JavaScript?
  • Android SQLite issue - table ... no tiene una columna llamada
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.