5

Using Android LiveData I'd like to be able to unregister and register many BroadcastReceivers in the onInactive() and onActive() call backs. So I want to do something like this:

public class BroadcastRecieverLiveData extends LiveData<BroadCastReciever> {
    private BroadcastReciever reciever;
    private Context context;

    public BroadcastRecieverLiveData(Context context) {
        this.context = context;
    }

    @Override
    protected void onActive() {
        IntentFilter filter = new IntentFilter();
        filter.addAction("SOME_ACTION");
        filter.addAction("SOME_OTHER_ACTION");

        reciever = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                //do something based on the intent's action
            }
        };
        registerReceiver(reciever, filter);
    }

    @Override
    protected void onInactive() {
        if (reciever != null) {
            context.unregisterReceiver(reciever);
        }
    }
}

I was thinking this could be a design pattern to be clean up of code instead of relaying on onDestroy. What are your thoughts on using LiveData this way? There is an example of using it here

tynn
  • 38,113
  • 8
  • 108
  • 143
j2emanue
  • 60,549
  • 65
  • 286
  • 456

1 Answers1

6

I think for receivers, you should implement LifecycleObserver. As per LiveData documentation from Google codelab,

Caution: Storing a reference to a Context or View in a ViewModel can result in memory leaks. Avoid fields that reference instances of the Context or View classes. The onCleared() method is useful to unsubscribe or clear references to other objects with a longer lifecycle, but not for clearing references to Context or View objects.

So, You should not do context intensive operation in LiveData.

Instead, take an example of below implementation,

import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.OnLifecycleEvent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;

public class ReceiverManager implements LifecycleObserver {

    private final Context mContext;
    private final MyBrodacastReceiver myBrodacastReceiver;

    public ReceiverManager(LifecycleOwner lifecycleOwner,
                           Context context) {
        mContext = context;
        myBrodacastReceiver = new MyBrodacastReceiver();
        lifecycleOwner.getLifecycle().addObserver(this);

    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void registerYourReceiver() {
        mContext.registerReceiver(myBrodacastReceiver, new IntentFilter());
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void unRegisterYourReceiver() {
        mContext.unregisterReceiver(myBrodacastReceiver);
    }

    private static class MyBrodacastReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {

        }
    }
}

Thanks.

AndiGeeky
  • 11,266
  • 6
  • 50
  • 66
  • So what you wrote is a memory leak because the activity context is never released right – j2emanue Jun 09 '17 at 05:22
  • 1
    @ j2emanue: Pass `application context` not, `activity` context! – AndiGeeky Jun 09 '17 at 05:24
  • @ j2emanue : Refere codelab mentioned in answer. It has location listener attached to it. Instead, you can use your broadcast receiver! – AndiGeeky Jun 09 '17 at 05:25
  • @AndiGeeky so.. if you have a reference to Context here as well, how is that better than the code in the question? I mean, he can pass the application context there as well (using his code with extending livedata). What's the difference? – BVtp Mar 16 '19 at 12:41