2011-09-10 27 views
5

He estado leyendo mucho sobre hilos, manipuladores, trabucos, etc. y estoy muy confundido. En mi aplicación, quiero que la primera actividad inicie un trabajador en segundo plano. Este trabajador de fondo solicitará continuamente datos de un socket TCP y (con suerte) publicará la nueva información en el hilo de la interfaz de usuario a medida que lleguen los datos. Si el usuario hace una transición a una nueva actividad, el fondo necesita seguir haciéndolo, pero solo envía diferentes mensajes al hilo de la interfaz de usuario para que pueda actualizar el nuevo diseño en consecuencia.Android: ¿forma correcta de pasar un mensaje desde el hilo de fondo al hilo de la interfaz de usuario?

aquí es lo que tengo hasta ahora ... Esto está en mi archivo principal actividad

public class MyTCPTest extends Activity { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     // set the layout 
     setContentView(R.layout.main); 
     // create a handler to handle messages from bg thread 
     Handler handler = new Handler(); 

     BgWorkerThread bgw = new BgWorkerThread(); 
     bgw.start(); 
} 

en otro archivo defino mi subproceso de trabajo de fondo como este ...

public class BgWorkerThread extends Thread {  
@Override 
public void run(){ 

    while(true) 
    { 
     try { 
     // simulate a delay (send request for data, receive and interpret response) 
     sleep(1000); 

        // How do I send data here to the UI thread? 

     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Si la interfaz de usuario cambia a una actividad diferente ¿Esta cadena seguirá ejecutándose? Además, ¿cómo sabe este hilo a qué actividad enviar el mensaje? Obviamente, quiero que siempre envíe los datos a la Actividad que está actualmente activa. ¿Eso sucede automáticamente?

Finalmente, cuando la interfaz de usuario cambia a una actividad diferente, el bgworker necesita ser notificado para que pueda comenzar a solicitar datos que sean relevantes para el nuevo diseño de la actividad. ¿Cuál es la mejor manera de informar al trabajador sobre el cambio? ¿No podría simplemente crear un método público en la clase BgWorkerThread que podría invocarse cuando se carguen las Actividades?

Respuesta

1

Creo que está buscando un mecanismo de devolución de llamada UI. Respondí una pregunta similar aquí: Best way to perform an action periodically [while an app is running] - Handler?. Como puede ver, estoy enviando un mensaje a la interfaz de usuario desde el hilo de fondo creando una instancia de Handler y llamando al sendEmptyMessage(). Hay otros tipos de mensajes que puede enviar, pero este es un ejemplo trivial.

Espero que ayude.

+0

Travis gracias por el enlace, pero todavía estoy confundido. La diferencia es que todo tu código parece estar en la misma clase. Mi asistente social es su propia clase que amplía Thread. Esta es una clase separada de la clase de Actividad, entonces, ¿cómo puedo acceder al controlador de esa clase/actividad? – PICyourBrain

3

He ilustrado el mismo código y pasos más detallados en el siguiente SO Question. En resumen, con el fin de notificar a su interfaz de usuario y darle contexto diferente, sugiero lo siguiente:

  • tener un mapa que se asignan a un RequestID Handler (suponiendo que tiene el contexto de la solicitud id). Debería registrar el Manejador apropiado en la Actividad, así podría hacer que los manejadores se comportaran de manera diferente para cada Actividad (por ejemplo, actualizar varios elementos de la IU cuando recibiera la respuesta del servidor)
  • Cambiar a AsyncTask para Enhebrar Modelo ya que tiene onProgressUpdate método que hace que sea más fácil de código con el fin de notificar al hilo de interfaz de usuario desde el subproceso de fondo

Aquí está el talón/pseudocódigo para su BackgroundThread

public class ResponseHandler extends AsyncTask<Void, String, Integer> { 
    boolean isConnectionClosed = false; 
    Map<Integer, Handler> requestIdToMapHandler; 

    public ResponseHandler() { 
     this.requestIdToMapHandler = new HashMap<Integer, Handler>(); 
    } 

    @Override 
    protected Integer doInBackground(Void... params) { 
     int errorCode = 0; 

     try { 
      // while not connection is not close 
      while(!isConnectionClosed){ 
       // blocking call from the device/server 
       String responseData = getResponse(); 

       // once you get the data, you publish the progress 
       // this would be executed in the UI Thread 
       publishProgress(responseData); 
      } 
     } catch(Exception e) { 
      // error handling code that assigns appropriate error code 
     } 

     return errorCode; 

    } 

    @Override 
    protected void onPostExecute(Integer errorCode) { 
     // handle error on UI Thread 
    } 

    @Override 
    protected void onProgressUpdate(String... values) { 
     super.onProgressUpdate(values); 
     String responseData = values[0]; 

     // the response contains the requestId that we need to extract 
     int requestId = extractId(responseData); 

     // next use the requestId to get the appropriate handler 
     Handler uiHandler = getUIHandler(requestId); 

     // send the message with data, note that this is just the illustration 
     // your data not necessary be jut String 
     Message message = uiHandler.obtainMessage(); 
     message.obj = responseData; 
     uiHandler.sendMessage(message); 
    } 

    /*** 
    * Stub code for illustration only 
    * Get the handler from the Map of requestId map to a Handler that you register from the UI 
    * @param requestId Request id that is mapped to a particular handler 
    * @return 
    */ 
    private Handler getUIHandler(int requestId) { 
     return null; 
    } 

    /*** 
    * Stub code for illustration only, parse the response and get the request Id 
    * @param responseId 
    * @return 
    */ 
    private int extractId(String responseId) { 
     return 0; 
    } 

    /*** 
    * Stub code for illustration only 
    * Call the server to get the TCP data. This is a blocking socket call that wait 
    * for the server response 
    * @return 
    */ 
    private String getResponse() { 
     return null; 
    } 
} 
0

puede utilizar

runOnUIThread(new Runnable { 

public void run() { 
//Update your UI here like update text view or imageview etc 

} 

}); 
Cuestiones relacionadas