2012-01-19 19 views
8

Traté de referir una pregunta similar en SO, pero no recibí ninguna ayuda.Devolver datos de AsyncTask Android

En mi aplicación de Android, planeo implementar Cita reciente que el usuario ha visitado, es decir, similar a páginas visitadas recientemente en la web.

Los siguientes son los pasos que sigo:

1.) Cada vez que el usuario abre cualquier punto de vista de la empresa, buscar a los símbolos de la empresa a partir de la base de datos

2.) A continuación, almacenar el símbolo actual a lo largo de con dateTime en la base de datos.

3.) Para todos los símbolos obtienen de la base de datos, Fetch su current value y %Change y visualización Nombre de la compañía, el valor actual y el% de cambio en una lista.

El problema surge en la clase ASyncTask, ya que el método postExecute no permite que su tipo de devolución sea distinto 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; 
      } 
     } 
    } 
+0

Será mejor si se utiliza BroadCasteReceiver http://developer.android.com/reference/android/content/BroadcastReceiver .html .. Le permite pasar datos a través de la intención. – ngesh

Respuesta

8

postExecute() no puede devolver un valor, porque ¿quién o qué sería volver a? Su método original que invoca a AsyncTask se ha ido porque su AsyncTask se está ejecutando en segundo plano. Es un significado asíncrono 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 a lo que devolverlo.

En su lugar, su AsyncTask necesita una referencia de regreso a su Actividad u otro objeto para que pueda publicar sus valores de nuevo. En su código, las líneas después de llamar a execute() no pueden estar allí porque su tarea no ha finalizado. En su lugar, debe crear un método llamado updateSymbol (currentPrice, percentChange), mover todo ese código debajo de execute() allí, y en su AsyncTask debe pasar una referencia a la actividad. Luego llame a updateSymbol (currentPrice, percentChange) desde el método onPostExecute().

Pero, tenga cuidado si tiene una referencia de referencia a una Actividad que se puede destruir mientras DoInBackground() se está ejecutando, y cuando se ejecuta postExecute() simplemente debe soltar los resultados o no intentar actualizar la UI. Por ejemplo, el usuario gira su teléfono causando la destrucción de la actividad. Encuentro que es mejor mantener una referencia a AsyncTask en la actividad para que pueda cancelarla() si se destruye la Actividad. Puede llamar AsyncTask.cancel() a continuación, comprobar si su tarea fue cancelada 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 mantener fácilmente un seguimiento de AsyncTasks ejecutando:

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 consejos rápidos. No es necesario ejecutar (new String [] {"blah" + blah}). Varargs en Java te permite hacer esto. ejecutar ("blah" + blah). También está atrapando excepciones y continuando sin realmente manejarlas. Será difícil cuando algo realmente suceda porque tu aplicación los atrapa y continúa como si nada hubiera pasado.Si obtiene 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 haga lo siguiente. Mueva los bloques de captura al final de los métodos.

+0

Thnx tanto. Soy nuevo en el desarrollo de Android y trato de entender esto. ¿A qué te refieres con ** en tu AsyncTask debes pasar una referencia a la Actividad ** ???? – GAMA

+0

DownloadRecentQuote task = new DownloadRecentQuote (esto) suponiendo que está ejecutando esto desde dentro de una actividad.Si no está ejecutando DownloadRecentQuote en una actividad, puede pasar una referencia a la instancia que está creando la instancia de DownloadRecentQuote, y luego descubrir la forma de actualizar la interfaz de usuario desde allí. Parece que está creando DownloadRecentQuote en una actividad porque veo una variable de lista con un adaptador. – chubbsondubs

3

Básicamente, AsyncTask.onPostExecute() es donde se hace lo que se quiera después de ejecutar DoInBackground() de AsyncTask y se devuelve el resultado de la ejecución. Esto debería ser considerado la mejor práctica.

Cuando se llama a AsyncTask(). Execute() desde el subproceso de UI (tenga en cuenta que este método debe invocarse desde el subproceso de UI), el marco de Android crea un subproceso de trabajo y comienza a ejecutar lo que escribió en AsyncTask.doInBackground () en este hilo de trabajo. En este punto (después de llamar a la nueva AsyncTask(). Execute()), el subproceso de UI continúa ejecutando el código después de la nueva AsyncTask(). Execute(). Entonces, ahora, durante el tiempo de ejecución, tiene dos hilos (UI e hilo 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 hilo de la interfaz de usuario?

El punto donde termina su subproceso de trabajo (doInBackground()) y vuelve al subproceso de la interfaz de usuario es AysncTask.onPostExecute(). Se garantiza que este método será llamado por el marco en el subproceso de interfaz de usuario tan pronto como finalice AsyncTask. En otras palabras, no nos importa dónde y cuándo se llama a AsyncTask.onPostExecute() en tiempo de ejecución, solo debemos garantizar que se llamará finalmente en algún momento en el futuro. Esta es la razón por la cual este método no devuelve un resultado de ejecución; en su lugar, requiere que el resultado de la ejecución se transfiera como el único parámetro de método de doInBackground().

Además, la API de Android proporciona una manera de devolver un resultado de la 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(); 

tener en cuenta que AsyncTask.get() bloqueará la ejecución del subproceso de llamada, y probablemente obtendrá una excepción ANR si la llama en el hilo de UI. Esta es la carga útil de usar AsyncTask.get(), al invocarlo en el subproceso UI, en realidad está haciendo que su AsyncTask (subproceso de trabajo) se ejecute de forma sincronizada con el subproceso de interfaz de usuario (haciendo que el subproceso de la interfaz de usuario espere). En resumen, esto es factible pero no recomendado.

+0

No creo que 'myAsyncTask.get()' bloqueará la IU durante mucho tiempo, ya que solo obtiene los datos calculados de 'onPostExecute()'. –

+0

Excepto en la parte de la línea 14 "el futuro", su respuesta es perfecta. –

1

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

He creado una tipo de actividad que tiene un método onStart() y una clase separada para el AsyncTask. Según mi prueba, después del método doInbackground() el resultado se enviará a la actividad primero y luego se ejecutará onPostExecute(). Esto se debe a que, a partir de logcat, primero tengo mis primeros datos de respuesta (enviados por el servidor), luego esta respuesta se mostrará nuevamente desde la actividad y la última aparecerá en el mensaje onPostExecute().

Código de la actividad: Código

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

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