2010-07-14 6 views
11

A pesar de similar question was asked, tengo la situación differnet: Mi aplicación consiste principalmente en un fondo Service. Quiero comenzar actividades externas y obtener resultados de nuevo.Analógico de startActivityForResult for Service

veo varias opciones:

  1. Crear y mantener ficticia Activity referencia a ella para el uso de su startActivityForResult. Esto consume mucha memoria, como sabemos.

  2. Use Broadcast Intents en lugar de la infraestructura de resultados de Android: solicite a las actividades del cliente que transmitan sus resultados antes del cierre. Este tipo de rompe la idea y no tan eficiente en el rendimiento.

  3. Utilice Instrumentation directamente - intente copiar el código de startActivityForResult en mi Servicio.

  4. Usar interfaces de servicio - serializar y agregar la conexión AIDL a la intención de iniciar una actividad. En este caso, Activity debería call Service directly en lugar de proporcionar el resultado.

El tercer enfoque se siente más cercano a Android para mí, pero no estoy seguro si es posible hacerlo - Servicio no tiene su instrumentación y aplicación por defecto parece volver siempre nula.

¿Quizás tenga alguna otra idea?

+0

Se puede lograr con un simple corte, mediante el uso de SharedPreferences, [SO] (http://stackoverflow.com/a/31461941/4859873) –

Respuesta

3

Creo que la opción 2 es la forma más idiomática en Android. El uso de startActivityForResult desde Activity es una llamada síncrona/de bloqueo, es decir, la actividad primaria espera y no hace nada hasta que el elemento secundario finalice. Cuando trabaje desde un Service e interactúe con actividades, realiza principalmente llamadas asíncronas/no bloqueantes, es decir, el servicio solicita que se realice algún trabajo y luego espera una señal para indicarle que puede continuar.

Si está utilizando el android local service pattern, puede hacer que sus actividades adquieran una referencia del Service y luego llamar a una función específica después de que haya realizado su trabajo. Intentar su opción 3 sería contrario a lo que el marco proporciona para usted.

+1

¡Gracias por tus pensamientos! Ahora elijo entre 2 (más fácil de implementar) y 4 (más seguro/privado y debería ser más rápido). Realmente no estoy de acuerdo con que startActivityForResult esté bloqueando (porque usa la función de devolución de llamada, no el valor del resultado), y también la instrumentación está en API pública =) ¡Gracias! –

+1

Quise decir que no está bloqueando en el sentido tradicional (por ejemplo, una llamada de bloqueo io). Está bloqueando de la manera conceptual en que lo usa. – Qberticus

+0

@Qberticus El enlace que proporcionó solo vincula a una página de muestras genéricas. –

16

He estado pensando en esto recientemente al implementar account authenticators con flujos de autorización de tres patas. Volver a enviar el resultado al servicio para su procesamiento es mejor que procesarlo en la actividad. También proporciona una mejor separación de preocupaciones.

No está claramente documentado, pero Android proporciona una forma sencilla de enviar y recibir resultados en cualquier lugar (incluidos los servicios) con ResultReceiver.

He encontrado que es mucho más limpio que pasar actividades, ya que eso siempre conlleva el riesgo de filtrar esas actividades. Además, llamar a métodos concretos es menos flexible.

Para utilizar ResultReceiver en un servicio, tendrá que hacerla una subclase y proporcionar una manera de procesar el resultado recibido, por lo general en una clase interna:

public class SomeService extends Service { 

    /** 
    * Code for a successful result, mirrors {@link Activity.RESULT_OK}. 
    */ 
    public static final int RESULT_OK = -1; 

    /** 
    * Key used in the intent extras for the result receiver. 
    */ 
    public static final String KEY_RECEIVER = "KEY_RECEIVER"; 

    /** 
    * Key used in the result bundle for the message. 
    */ 
    public static final String KEY_MESSAGE = "KEY_MESSAGE"; 

    // ... 

    /** 
    * Used by an activity to send a result back to our service. 
    */ 
    class MessageReceiver extends ResultReceiver { 

     public MessageReceiver() { 
      // Pass in a handler or null if you don't care about the thread 
      // on which your code is executed. 
      super(null); 
     } 

     /** 
     * Called when there's a result available. 
     */ 
     @Override 
     protected void onReceiveResult(int resultCode, Bundle resultData) { 
      // Define and handle your own result codes 
      if (resultCode != RESULT_OK) { 
       return; 
      } 

      // Let's assume that a successful result includes a message. 
      String message = resultData.getString(KEY_MESSAGE); 

      // Now you can do something with it. 
     } 

    } 

} 

Al iniciar una actividad en el servicio, crear un receptor de resultado y el paquete en los extras intención:

/** 
* Starts an activity for retrieving a message. 
*/ 
private void startMessageActivity() { 
    Intent intent = new Intent(this, MessageActivity.class); 

    // Pack the parcelable receiver into the intent extras so the 
    // activity can access it. 
    intent.putExtra(KEY_RECEIVER, new MessageReceiver()); 

    startActivity(intent); 
} 

y, por último, en la actividad, descomprimir y utilizar el receptor ResultReceiver#send(int, Bundle) para enviar un resultado de nuevo.

Puede enviar un resultado en cualquier momento, pero aquí he elegido para hacerlo antes de terminar:

public class MessageActivity extends Activity { 

    // ... 

    @Override 
    public void finish() { 
     // Unpack the receiver. 
     ResultReceiver receiver = 
       getIntent().getParcelableExtra(SomeService.KEY_RECEIVER); 

     Bundle resultData = new Bundle(); 

     resultData.putString(SomeService.KEY_MESSAGE, "Hello world!"); 

     receiver.send(SomeService.RESULT_OK, resultData); 

     super.finish(); 
    } 

} 
+0

gracias por la solución! Una cosa: RESULT_OK debe ser ** - 1 ** de acuerdo con Activity.java – Philipp

+0

Buen punto. Creo que en este caso es posible usar cualquier valor, pero es mejor mantenerse coherente con lo que proporcione la plataforma. He actualizado la respuesta. También podría usar Activity.RESULT_OK directamente. –

+0

necesita agregar '@SuppressLint (" ParcelCreator ")' antes de la clase 'MessageReceiver'; de lo contrario, le pedirá que haga un CREATOR como [ResultReceiver] (https://developer.android.com/reference/android/os/ ResultReceiver.html) implementa Parcelable. Gracias por la respuesta. – ArJ

Cuestiones relacionadas