Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Make an Event Bus With Google's LiveData

DZone's Guide to

How to Make an Event Bus With Google's LiveData

Event buses can sometimes cause memory leaks or other lifecycle problems. See how to avoid this by using the LiveData library.

· Mobile Zone ·
Free Resource

At Google I/O this year, Google announced a new set of architecture libraries. One of the new components they included is called LiveData. It can be used to help manage propagating data to your views, while respecting the activity and fragment lifecycles. Until now, you typically had to manage all of this on your own. Or more commonly, many developers neglected to handle these scenarios at all. This resulted in memory leaks, among other issues.

LiveData can be used to resolve these issues, in conjunction with the LifecycleRegistryOwner. To add these components to your project, you can follow Google’s instructions.

To set up the event bus, we need to implement LifecycleRegistryOwner on our Activities and Fragments. To simplify this, I have a BaseActivity class, and a BaseFragment class which can be extended from. These classes will implement the LifecycleRegistryOwner interface, so all of my Activities and Fragments don’t have to. You can see these implementations below:

public abstract class BaseActivity extends AppCompatActivity implements LifecycleRegistryOwner {

    private final LifecycleRegistry mRegistry = new LifecycleRegistry(this);

    @Override
    public LifecycleRegistry getLifecycle() {
        return mRegistry;
    }
}
public abstract class BaseFragment extends Fragment implements LifecycleRegistryOwner {

    private final LifecycleRegistry mRegistry = new LifecycleRegistry(this);

    @Override
    public LifecycleRegistry getLifecycle() {
        return mRegistry;
    }
}


The other piece is my LiveData class. I want to be able to send any type of data through my event bus, so I will use the Object class for my LiveData. I named my implementation EventLiveData:

public class EventLiveData extends LiveData<Object> {

    private final int mSubject;

    public EventLiveData(@LiveDataBus.Subject int subject) {
        mSubject = subject;
    }

    public void update(Object object) {
        postValue(object);
    }

    @Override
    public void removeObserver(Observer<Object> observer) {
        super.removeObserver(observer);
        if (!hasObservers()) {
            LiveDataBus.unregister(mSubject);
        }
    }
}


My event bus uses integer constants to define different subjects. These subjects are what define the type of event you are observing. When your LifecycleRegistryOwner is destroyed, its Observers will be removed. I override the  removeObserver  method so that the EventLiveData can remove itself from the event bus.

The reason I remove the EventLiveData from the event bus is because it will send out whatever its current value is to new observers. This behavior is fine if you’re loading data, but I’m also using it to send events like tapping on a button. I don’t want those events to get repeated.

With these components included, my new event bus class looks like this:

public final class LiveDataBus {

    private static SparseArray<EventLiveData> sSubjectMap = new SparseArray<>();

    public static final int SUBJECT_DATA_LOADED = 0, SUBJECT_DOWNLOAD_COMPLETE = 1;

    @Retention(SOURCE)
    @IntDef({SUBJECT_DATA_LOADED, SUBJECT_DOWNLOAD_COMPLETE})
    @interface Subject {
    }

    private LiveDataBus() {
        // hidden constructor
    }

    /**
     * Get the live data or create it if it's not already in memory.
     */
    @NonNull
    private static EventLiveData getLiveData(@Subject int subjectCode) {
        EventLiveData liveData = sSubjectMap.get(subjectCode);
        if (liveData == null) {
            liveData = new EventLiveData(subjectCode);
            sSubjectMap.put(subjectCode, liveData);
        }

        return liveData;
    }

    /**
     * Subscribe to the specified subject and listen for updates on that subject.
     */
    public static void subscribe(@Subject int subject, @NonNull LifecycleRegistryOwner lifecycle, @NonNull Observer<Object> action) {
        getLiveData(subject).observe(lifecycle, action);
    }

    /**
     * Removes this subject when it has no observers.
     */
    public static void unregister(@Subject int subject) {
        sSubjectMap.remove(subject);
    }

    /**
     * Publish an object to the specified subject for all subscribers of that subject.
     */
    public static void publish(@Subject int subject, @NonNull Object message) {
        getLiveData(subject).update(message);
    }
}


To use the LiveDataBus, you subscribe to a subject with a LifecycleRegistryOwner (typically a Fragment or Activity). Then, implement the Observer callback to do whatever you want with the data. Since the bus uses Objects, you need to cast it to whatever type of data you’re receiving. Here is an example:

//Example Activity
public class MyActivity extends BaseActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.myactivity);

        // with lambda
        LiveDataBus.subscribe(LiveDataBus.SUBJECT_DATA_LOADED, this, (data) -> {
                    Log.d("Testing my data", (String)data);
                });

        //without lambda
        LiveDataBus.subscribe(LiveDataBus.SUBJECT_DATA_LOADED, this, new Observer<Object>() {
                    @Override
                    public void onChanged(@Nullable Object data) {
                        Log.d("Testing my data", (String)data);
                    }
                });
    }
}

//Example data published (this could be anywhere in your app)
LiveDataBus.publish(LiveDataBus.SUBJECT_DATA_LOADED, "Hello world");


The way that I am using LiveData is not how it was intended to be used, but it does exactly what I need - it takes care of the lifecycle issues for me. Now I don’t have to worry about my event bus causing memory leaks, or any other lifecycle problems, especially if someone other than me is using this code. Now, it’s foolproof!

Topics:
android ,mobile ,mobile app development ,event bus ,mobile security

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}