Did you ever heard about Publish-Subscribe pattern in Software architecture?
Yes. It’s a messaging pattern where the senders of the message, called the publishers will never know who are going to receive those messages and the receivers, also known as the subscribers, won’t know who sent those messages as well.
The publishers will just send the message, without knowing who is gonna receive it. They do their work right.
On the other hand, the receivers, I mean the subscribers, will subscribe what kind of message they want to get. Doesn’t matter who’ll send them. Well, why should they care? They’re gonna get what they need, right? 😀
Okay, let’s change the perspective a little. Think of an event as a message here. Now think about the publish-subscriber pattern. Yes, you got it right!
There will be event publishers instead of message publishers. And the subscribers will receive events instead of messages. So that whenever an event is published (of course by the publishers), the subscribers can receive that event and execute their code.
Here comes the awesomeness of the EventBus dependency for Android. It enables you to use publish-subscribe software architecture pattern. I’m using this library for several days and I’m just amazed. I don’t have to worry about event handlers now, I don’t need fragment interaction listeners, my code is clean and organised.
Okay let’s see how can we use this api in real life project. There’s a getting started page where you can find the instructions to use it. I recommend you to take a look on that page.
I’m creating a real world project so that we can get a hands on experience before we can use it.
First thing first, Let’s create an Android Studio project. I’m naming my project as EventBusDemo.
Add EventBus dependency on our app level build.gradle file:
compile 'org.greenrobot:eventbus:3.0.0'
We’ll have a textview and a button on our activity and a fragment (It’ll contain a textview and a button) so that we can illustrate the interaction between activity and fragment with eventbus as well.
Our goal is, whenever a button is clicked, all of the textviews (regardless activity textview or fragment textview) will be updated. So we have to post an even when a button is clicked, right? Then all of the methods that subscribes that event will update the textviews. or do whatever they meant to do.
Let’s create our event first. It’s a plain old Java object(pojo). We name it MessageEvent
MessageEvent.java
package net.toracode.eventbusdemo.events; public class MessageEvent { private String message; public MessageEvent(String message) { this.message = message; } public String getMessage() { return message; } }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="net.toracode.eventbusdemo.MainActivity"> <TextView android:textSize="15sp" android:id="@+id/activity_textview" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="TextView from activity" /> <Button android:id="@+id/activity_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/activity_textview" android:text="Activity Button" /> <RelativeLayout android:layout_marginTop="50dp" android:background="@color/colorAccent" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/fragmentContainerLayout" android:layout_below="@id/activity_button" /> </RelativeLayout>
fragment_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" tools:context="net.toracode.eventbusdemo.MainFragment"> <TextView android:textColor="@android:color/white" android:textSize="15sp" android:id="@+id/fragment_textview" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="TextView from Fragment" /> <Button android:id="@+id/fragment_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/fragment_textview" android:text="Fragment Button" /> </RelativeLayout>
MainActivity.java
package net.toracode.eventbusdemo; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; import net.toracode.eventbusdemo.events.MessageEvent; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; public class MainActivity extends AppCompatActivity { private TextView activityTextView; private Button activityButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // init components this.activityTextView = (TextView) this.findViewById(R.id.activity_textview); this.activityButton = (Button) this.findViewById(R.id.activity_button); // register eventbus EventBus.getDefault().register(this); this.getSupportFragmentManager().beginTransaction().replace(R.id.fragmentContainerLayout,new MainFragment()).commit(); activityButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EventBus.getDefault().post(new MessageEvent("Activity Button Clicked!")); } }); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent messageEvent){ this.activityTextView.setText(messageEvent.getMessage()); } }
We’ve registered eventbus on onCreate(). Best practice is to do it on onStart(). But it’s just a demo.
We have a method onMessageEvent() that subscribes MessageEvent, taking a MessageEvent object as a argument. That means whenever a message event will be posted this method will be executed. We’ve updated the textview with the message from message event.
We’ve implemented another subscriber method to update fragment textview in MainFragment.java.
So these two subscriber method will be executed without knowing who is the publishers or what’s inside this event. It’s just waiting for the MessageEvent to be published.
MainFragment.java
package net.toracode.eventbusdemo; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import net.toracode.eventbusdemo.events.MessageEvent; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; public class MainFragment extends Fragment { private TextView fragmentTextView; private Button fragmentButton; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_main, container, false); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // init components this.fragmentTextView = (TextView) getView().findViewById(R.id.fragment_textview); this.fragmentButton = (Button) getView().findViewById(R.id.fragment_button); // Register eventBus EventBus.getDefault().register(this); this.fragmentButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EventBus.getDefault().post(new MessageEvent("Fragment Button Clicked!")); } }); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent messageEvent){ this.fragmentTextView.setText(messageEvent.getMessage()); } }
We’ve posted event with custom message on onClickListeners of both activityButton and fragmentButton. When someone click those buttons, an event will be posted with a message. and those methods that subscribes that event will be executed, in this case, the textviews will be updated. And that’s how it works!