unregisterReceiver(receiver) in onPause causes the receiver not to register

jameson2012 :

Hello fellow overflowers. I have a problem with a BroadcastReciever - there are, I know a multitude of questions and answers exist because I have been trying each one for the last 2 days so please if you do want to mark this as a duplicate check that the code doesn't match what I've already written (as I have almost certainly copied it form a SO answer).

And so here we go:

I want to detect the lock screen being turned on or off in my base activity - from which all my other activities extend

public abstract class BaseActivity extends AppCompatActivity{////

in here I have member variables

BroadcastReceiver receiver;
IntentFilter filter;

which I assign like this:

receiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                        //do some code
                    } else {
                       //do something else
                    }
                }
            };


filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);

This works as expected if I put it in onCreate() or in onResume() and I can successfully call registerReceiver(receiver, filter) in either create or resume and it works fine.

I don't want this to be active when the app is paused, so as all the various answers and tutorials suggest I unregister it in onPause

     @Override
        protected void onPause() {
//I have commented both out to demonstrate that I have tried both before and after the calling the superclass
      //    this.unregisterReceiver(receiver);
            super.onPause();
    //      unregisterReceiver(receiver);

        }

When I include this unregister call it stops the registration from ever happening. I have tried registering in onCreate,onResume and both. I can move around the combination all through the activity but as soon as I introduce the unregister it doesn't work at all - not even an error or a crash (otherwise I would include a stack trace here).

The closes thing I have been able to achieve is:

receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
  if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
  //do some code 
  unregisterReceiver(receiver);

by putting the unregister into the onRecieve I am am able to deregister the receiver and re-register it correctly, EXCEPT that if I have multiple activities in the stack for my app I get a memory leak error and the trace requests, rather patronisingly if I have forgotten to add an unregister call.

So has anyone any idea why adding the unregister call to the onPause() would cause the receiver to cancel altogether?

H.Taras :

As I thought, you have this issue because system sends ACTION_SCREEN_OFF after onStop() method, so you can not handle it, because you already unregistered it. Don't know why you can not handle SCREEN_ON event, because when I tested this, I see that system send it after onResume(). This is what I have in my logs:

D/TEST: onPause:
D/TEST: onStop:
D/TEST: onReceive: action = android.intent.action.SCREEN_OFF
D/TEST: onStart:
D/TEST: onResume:
D/TEST: onReceive: action = android.intent.action.SCREEN_ON

I think, it was sent earlier than onResume called, but delivered after it.

So, my solution is to register receiver in onCreate(@Nullable Bundle savedInstanceState) and unregister in onDestroy(), that is how I got this logs.

Update 1: This is how I registered receiver in onCreate(@Nullable Bundle savedInstanceState)

IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(new TestReceiver(), filter);

Update 2: I missed, that you don't need to receive events if your activity is paused. If there is some code that you don't want to execute when activity is paused, I can suggest you to create simple enum:

enum ActivityState { STARTED, RESUMED, PAUSED, STOPPED }

and private variable ActivityState currentState. Then in lifecycle methods assign proper state to currentState. Then in your receiver onReceive() method you can check current state and do what you want depend on state. Logs when app is in active:

D/TEST: onReceive: action = android.intent.action.SCREEN_OFF, current Activity state = STOPED
D/TEST: onReceive: action = android.intent.action.SCREEN_ON, current Activity state = RESUMED

And logs when app was not active:

D/TEST: onReceive: action = android.intent.action.SCREEN_OFF, current Activity state = STOPED
D/TEST: onReceive: action = android.intent.action.SCREEN_ON, current Activity state = STOPED

I hope it helps!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=150124&siteId=1