¿Cuándo registrar / anular el registro de receptores de difusión creados en una actividad?

79

Tengo la necesidad de crear un receptor de transmisión personalizado en el evento onCreate de una actividad y obviamente necesito cancelar el registro del receptor de transmisión en el evento onDestroy de la actividad.

Para mayor claridad, este es un fragmento del código que uso

public class AnActivity extends Activity {
    private ResponseReceiver receiver;

    public class ResponseReceiver extends BroadcastReceiver {
           public static final String ACTION_RESP =
              "mypackagename.intent.action.MESSAGE_PROCESSED";

           @Override
            public void onReceive(Context context, Intent intent) {
// TODO Start a dialogue if message indicates successfully posted to server
            }
    }   

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        IntentFilter filter = new IntentFilter(ResponseReceiver.ACTION_RESP);
        filter.addCategory(Intent.CATEGORY_DEFAULT);
        receiver = new ResponseReceiver();
        registerReceiver(receiver, filter);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
    }

He leído que los eventos onPause / onResume y onStart / onStop para la actividad también deben registrar y anular el registro del receptor de transmisión.

Tengo muchas ganas de entender cuál se considera la mejor práctica para esto y por qué.

jamesc
fuente
Es porque cuando onDestroy()se llama, el receptor no escuchará más eventos.
de_billa_

Respuestas:

91

Debe registrar y anular el registro de sus destinatarios onStart()y onStop().

La única razón por la que una Actividad registraría BroadcastReceivers es para usar los eventos de alguna manera en la actividad actual, para informar al Usuario de un evento. Si onStop()ha sido llamado, entonces Activityya no está en primer plano y, por lo tanto, no puede actualizar el Usuario.

Si desea recibir eventos de transmisión en segundo plano, debe considerar usar un servicio como se indica aquí .

Como dice Konstantin, onDestroy()no se garantiza que se le llame, y podría continuar recibiendo transmisiones durante mucho tiempo, cuando Activityya no esté abierto.

Pistas nevadas
fuente
3
¿Estás sugiriendo que me registre en onResume EN LUGAR de onCreate o también? ¿Se llama siempre a onResume cuando se crea una actividad?
jamesc
9
Debe registrarse onResume sí, onResume () siempre se invoca en la actividad que se muestra (es el último método llamado antes de que aparezca su actividad ( developer.android.com/reference/android/app/Activity.html ) si solo se registra enCreate () y anular el registro de onPause (), luego, la próxima vez que la actividad se lleve al primer plano, no se volverá a llamar a onCreate () y no volverá a registrar el receptor. Y sí, me refiero EN LUGAR de, no lo hagas onCreate ().
SnowyTracks
1
@SnowyTracks: ¿puede comentar por qué es preferible realizar llamadas de registro de BroadcastReceiver en onResume / onPause en lugar de onStart / onStop? Al revisar la guía para desarrolladores de servicios vinculados, encontré esto . Hacia el final de esta sección, se recomienda realizar el enlace / desvinculación del servicio en onStart / onStop en lugar de onResume / onPause (por razones de rendimiento). Me pregunto si esto también se aplica a BroadcastReceivers. Gracias por adelantado.
Janus Varmarken
1
@jvmk De acuerdo, el documento de Android dice que haga esto en onStart y onStop, creo que en el 99% de los casos, hay poca diferencia, solo hay una diferencia en el comportamiento en las actividades de diálogo o se utilizan actividades de primer plano parciales. Pero actualizaré mi respuesta para que esté en línea con el documento de Android
SnowyTracks
1
Veo que editó el segundo párrafo ayer ... gracias por hacer un esfuerzo para obtener una respuesta más coherente. Pero todavía no explica por qué uno debería usar onStart / onStop en lugar de o en combinación con onResume / onPause , que era la pregunta del OP. En cambio, la explicación del segundo párrafo es igualmente cierta de onResume / onPause como de onStart / onStop: una vez que se llama a onPause, la actividad ya no está en primer plano. Así que nos quedamos sin un "por qué" para su recomendación.
LarsH
19

Como onDestroy()no está garantizado para ser llamado, debe usar onPause()para cancelar el registro. Considere el ciclo de vida de su receptor de transmisión: ¿Necesita que esté activo, solo cuando su actividad está en primer plano? Entonces usa onResume()/onPause()

Konstantin Pribluda
fuente
¿Qué pasa si todavía necesitamos actualizar el contenido en actividad incluso si la actividad está en segundo plano, porque el usuario puede reanudar la aplicación y los datos actualizados deberían mostrarse en ese caso?
Usman Rana
9

La documentación de Android no prescribe un solo lugar para registrar / anular el registro de receptores de transmisión, pero menciona tanto onStart()/ onStop()como onResume()/ onPause()como posibilidades.

El factor más importante para tomar esta decisión es, ¿cuándo debe su receptor poder hacer su trabajo? Esto determinará cuándo registrarlo y anular el registro.

  • ¿El receptor necesita hacer algo con la transmisión solo cuando la actividad está enfocada? Si es así, puede registrarlo / anular el registro en onPause()/ onReceive(). (También puede usar una vida útil más larga como onStart()/ onStop(), pero luego debe verificar durante el receptor onReceive()si la actividad está enfocada).

  • ¿El receptor necesita hacer algo cuando está visible, incluso si no tiene el foco (por ejemplo, cuando se muestra un diálogo)? Si es así, use onStart()/ onStop()(o una vida útil más larga, pero nuevamente, el receptor onReceive()debe verificar si la actividad es visible).

  • ¿El receptor necesita conocer la transmisión incluso cuando la actividad no es visible? Por ejemplo, ¿necesita recordar que ha sucedido algo, de modo que cuando la actividad se vuelva visible, pueda reflejar el estado de cosas resultante? Entonces necesita usar onCreate()/ onDestroy()para registrarse / anular el registro. (Tenga en cuenta que hay otras formas de implementar este tipo de funcionalidad).

Si te registras onStart(), no los registres también onResume(), porque eso sería redundante: onResume()nunca se llama sinonStart() ser llamado primero.

También tenga en cuenta que es mejor mantener onPause () lo más ligero posible :

La ejecución de onPause () es muy breve y no necesariamente ofrece suficiente tiempo para realizar operaciones de guardado. Por esta razón, no debe usar onPause () para guardar datos de aplicaciones o usuarios, realizar llamadas de red o ejecutar transacciones de bases de datos; es posible que dicho trabajo no se complete antes de que se complete el método. En su lugar, debe realizar operaciones de apagado de carga pesada durante onStop ().

Es cierto que onDestroy()se no garantiza que es llamado si el sistema mata a su proceso con el fin de ahorrar memoria. Sin embargo, si el proceso se mata, el proceso no recibirá transmisiones de todos modos. En ese caso, ¿es realmente necesario anular el registro de los receptores de transmisión?

LarsH
fuente
Gracias por su respuesta a mi pregunta, pero su respuesta es confusa y no estrictamente precisa. Dice que If you register in onStart(), don't also register them in onPause(), because that would be redundant: onPause() is never called without onStart() being called first.es simplemente ilógica y confusa, especialmente cuando la respuesta aceptada es perfectamente precisa.
jamesc
@jamesc: Vaya, me refiero a onResume en lugar de onPause. Tienes razón, eso es un poco confuso. Arreglado ahora. En cuanto a la respuesta aceptada, la he comentado. Creo que esta respuesta agrega información significativa y relevante que la aceptada no ofrece.
LarsH
5

Android puede matar su aplicación omitiendo el onStop()método. La mejor manera de resolver esa situación es registrarse BroadcastReceiveren el onResume()método y cancelar el registro onPause().

ukson
fuente
1
Yo también estoy haciendo esto. Tenido problemas con onStop()aswell
Vygintas B
0

Debe registrar y anular el registro de su transmisión en los métodos onResume () y onPause ().

si se registra en onStart () y lo cancela en onStop (). esa vez obtendrá el siguiente problema.

si la pantalla de su dispositivo está bloqueada, se llama a onStop () y si desbloquea esa hora, nunca se llama a onStart (). es por eso que tiene que registrarlo y cancelarlo en los métodos onResume () y onPause ().

Mayuresh Deshmukh
fuente