2012-04-26 9 views
36

Estoy usando un IntentService para manejar las comunicaciones de red con un servidor a través de JSON. La parte JSON/servidor funciona bien, pero tengo problemas para volver a obtener los resultados donde se necesitan. El siguiente código muestra cómo estoy comenzando el servicio de intento desde dentro de OnClick(), y luego hago que el servicio actualice una variable global para retransmitir los resultados a la actividad principal.¿Cómo obtener resultados de un IntentService en una actividad?

public class GXActivity extends Activity { 

    private static final String TAG = "GXActivity"; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     // === called when the activity is first created 

     Log.i(TAG, "GXActivity Created"); 

     super.onCreate(savedInstanceState); 
     setContentView(R.layout.start); 

     View.OnClickListener handler = new View.OnClickListener() { 
      public void onClick(View v) { 

       // === set up an application context to hold a global variable 
       // === called user, to contain results from the intent service 
       GXApp appState = ((GXApp) getApplicationContext()); 
       User user = new User(-1); // initialize user id to -1 
       appState.setUser(user); 

       // === next start an intent service to get JSON from the server; 
       // === this service updates the user global variable with 
       // === results from the JSON transaction 
       Intent intent = new Intent(this, GXIntentService.class); 
       startService(intent); 

       // === check app context for results from intent service 
       appState = ((GXApp) getApplicationContext()); 
       if (appState.getUser().getId() != -1)... 

      } 
     } 
    } 
} 

El problema que estoy teniendo es que el servicio que analiza la intención JSON no consigue invocar hasta después onCreate() completa, por lo que mi código que está en busca de los resultados se ha quedado atascado viendo resultados sin inicializar.

¿Qué debo hacer de manera diferente para que se llame al servicio de intención antes de verificar los resultados? ¿Funcionaría si sacara el oyente click de la función onCreate()? ¿Hay otro/mejor para estructurar este código? Muchas gracias.

+1

vea esto puede ser útil http://stackoverflow.com/a/9089086/985143 –

Respuesta

78

Debería considerar la creación de su propia subclase ResultReceiver en su actividad. ResultReceiver implementa Parcelable por lo que se puede pasar desde su Activity a su Service como un extra en el Intent.

Tendrá que hacer algo como esto:

  1. Implementar una subclase de ResultReceiver dentro de su clase de actividad. El método clave para implementar es onReceiveResult(). Este método le proporciona un Bundle de datos de resultados que pueden usarse para pasar cualquier información que esté recuperando en su Service. Simplemente descomprima los datos que necesita y úselos para actualizar su actividad.

  2. En su actividad, cree una nueva instancia de su ResultReceiver personalizado y agréguelo al Intent que utiliza para iniciar su servicio.

  3. En onStartCommand() método de sus Service 's, recuperar el ResultReceiver aprobada en el Intent y almacenarlo en una variable miembro local.

  4. Una vez que su Service completa su trabajo, tienen que llamar send() en el ResultReceiver pasar todos los datos que desea enviar de nuevo a la actividad en un Bundle.

Este es un patrón bastante efectivo y significa que no está almacenando datos en desagradables variables estáticas.

+0

¡Gracias por la respuesta rápida! Dos preguntas de seguimiento. Primero, si cambio a usar extras como lo sugirió, ¿hay algún ejemplo de código bueno y simple del patrón que delineó? En segundo lugar, si quisiera mantener el enfoque de variable global (en este caso, bastante inocuo, ya que la información que contiene no cambia mucho o muy a menudo), ¿cómo lo haría? ¿Hay alguna manera de sacar el oyente de clic de onCreate(), o de lo contrario sincronizar la actividad y el servicio? – gcl1

+0

El problema fundamental que tiene es que el Servicio se ejecuta de forma completamente independiente de la Actividad y tarda un tiempo indeterminado en completarse. La solución "correcta" para este problema es el uso de algún tipo de mecanismo de devolución de llamada asincrónica (que es lo que el ResultReceiver hace por usted). La alternativa consiste en sondear repetidamente algún tipo de variable estática 'isRunning' en su actividad para detectar cuándo finaliza el servicio y luego leer los datos de otra variable estática. Sin embargo, eso es bastante ineficiente y probablemente requiera un hilo de fondo dedicado, no recomendado. – tomtheguvnor

+0

Lo intenté, pero acabo de comenzar aquí y aparentemente aún no tengo suficientes puntos de reputación. Pero tu respuesta fue excelente, y rompió la tuerca que me mantuvo despierto hasta las 3 am de anoche. ¡Gracias! – gcl1

7

Si todo lo que necesita hacer es obtener un servidor JSON del servidor sin bloquear el hilo de la interfaz de usuario, puede ser más simple simplemente usar AsyncTask.

+2

async-task El ciclo de vida de la tarea está vinculado al hilo que se está ejecutando, por lo que si giro la pantalla se relanzará. – hadi

11

Hay muchas maneras de hacer cosas en segundo plano obteniendo un resultado (AsyncTask, enlazar una actividad a un servicio ...), Pero si quieres MANTENER código de su IntentService puede simplemente:

1- enviar un intento de difusión (que contiene el estado de sus datos extendidos) al final de la obra en su IntentService

2- implementar un LocalBroadcastReceiver en su actividad que consume los datos de la Intención

Ésta es también la forma recomendada en la documentación oficial (si quieres MANTENER su IntentService):

https://developer.android.com/training/run-background-service/report-status.html

1

Puede usar la biblioteca Otto. Otto es un proyecto de código abierto diseñado para proporcionar una implementación de bus de evento para que los componentes puedan publicar y suscribirse a eventos.

+0

No estoy seguro de si Otto o GreenBus funcionarían dentro de la cadena de mensajes de IntentService. – Genc

+0

Funciona. He estado usando. –

Cuestiones relacionadas