EventBus Example
Android EventBus Tutorial and Examples.
This is an android GreenRobot EventBus tutorial and examples.
What is EventBus?
EventBus is a library for Java and Android that simplifies communication between various components or parts of an application.
For example is in android we have several components like:
- Activities.
- Fragments.
- Services.
- and Threads.
Why EventBus?
Normally it's not very straight forward to communicate between or among these components. Normally you are forced to write lots of boilerplate code. For example:
- To pass data between Activities you use Intents. To pass java objects you have to serialize and later deserialize them, thus leading to tight binding between the components.
- To pass data between Fragments you use Bundles.
- To pass data from Services you use Broadcast Managers.
These are all great, however we face the following issues:
- Coupled hard to maintain code.
- Lots of boilerplate code.
- Objects can easily be passed without serialization and deserialization.
Publish/subscribe models try to avoid this tight integration by relying on an event bus model. In this type of model, there are publishers and subscribers. Publishers are responsible for posting events in response to some type of state change, while subscribers respond to these events
Hence great developers have come with solutions such as the publish/subscribe pattern of communication. In these:
- Publishers publish or post events.
- Subscribers listen or subscribe to those events.
- Event hold the information we want to pass.
This solves the coupling problem by modularising the components. The events allow for isolation of dependencies on each side. The event result is a bus allowing for communication pipeline that allows for readable and maintainable application.
Thread Delivery
EventBus can handle threading for you: events can be posted in threads different from the posting thread. A common use case is dealing with UI changes.
EventBus is a powerful library that respects your threading requirements when used to communicate. It does this by providing several thread delivery modes:
1. ThreadMode: POSTING
In this mode the subscribers are called in the same thread that posted that event. This is the default mode for eventbus.
// ThreadMode is optional as this is the default mode
@Subscribe(threadMode = ThreadMode.POSTING)
public void onEvent(MessageEvent event) {
log(event.message);
}
2. ThreadMode: MAIN
In this mode the Subscribers will be called in the main thread.
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {
textView.setText(event.message);
}
3. ThreadMode: MAIN_ORDERED
In this mode the Subscribers will be called in the main thread but the event is always enqueued for later delivery to subscribers, so the call to post will return immediately.
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onEvent(MessageEvent event) {
textView.setText(event.message);
}
4. ThreadMode: BACKGROUND
In this mode the Subscribers will be called in a background thread.
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onEvent(MessageEvent event){
saveToDisk(event.message);
}
5. ThreadMode: ASYNC
In this mode the Event handler methods are called in a separate thread. This is always independent from the posting thread and the main thread.
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onEvent(MessageEvent event){
network.send(event.message);
}
Sticky Events
Stick events are events that EventBus will keep in memory and can be later delivered to subscribers or queried. Thus you don't have to write your own cache when working with data that are being emmitted continuosly like sensor data. EventBus can allow you work with latest emitted data through sticky events.
Here's how you post sticky event:
Then to subscribe:
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {
textField.setText(event.message);
}
Alternatives to GreenRobot EventBus
Here are some alternatives to GreenRobot EventBus:
No. | Alternative | Description |
---|---|---|
1. | Otto | This is Deprecated. |
2. | RxJava |
Installing EventBus
There are three ways of installing eventbus:
1. Via Gradle
If you are using gradle build system then here's the implementation statement. Check the latest version here.
2. Via Maven
In your pom.xml add:
<dependency>
<groupId>org.greenrobot</groupId>
<artifactId>eventbus</artifactId>
<version>3.1.1</version>
</dependency>
Here are EventBus examples:
Kotlin Android EventBus Example
Simple step by step eventbus examples for android.
Step 1: Install EventBus
Start by installing the eventbus as has been discussed above:
implementation "org.greenrobot:eventbus:${versions.eventbus}"
kapt "org.greenrobot:eventbus-annotation-processor:${versions.eventbusProcessor}"
Step 2: Design Layouts
(a). activity_empty.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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.example.eventbuskotlin.EmptyActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onPostStickyButtonClick"
android:text="@string/action_post_sticky"/>
</RelativeLayout>
(b). fragment_blank.xml
<FrameLayout 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"
tools:context="com.example.eventbuskotlin.BlankFragment">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment" />
</FrameLayout>
(c). activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
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="com.example.eventbuskotlin.MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onPostButtonClick"
android:text="@string/action_post" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onLaunchButtonClick"
android:text="@string/action_launch_activity" />
<FrameLayout
android:id="@+id/containerFragment"
android:layout_width="match_parent"
android:layout_height="250dp" />
</LinearLayout>
Step 3: Initialize EventBus
Initialize it in the onCreate()
method of the Application
class:
package com.example.eventbuskotlin
import android.app.Application
import org.greenrobot.eventbus.EventBus
class EventBusApp: Application() {
override fun onCreate() {
super.onCreate()
EventBus.builder()
// have a look at the index class to see which methods are picked up
// if not in the index @Subscribe methods will be looked up at runtime (expensive)
.addIndex(MyEventBusIndex())
.installDefaultEventBus()
}
}
Step 4: Create Fragments
Create two fragments:
(a). BlankBaseFragment.kt
package com.example.eventbuskotlin
import android.support.v4.app.Fragment
import android.util.Log
import android.widget.Toast
import org.greenrobot.eventbus.EventBus
abstract class BlankBaseFragment : Fragment() {
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
}
open fun handleEvent(event: SampleEvent) {
val className = this.javaClass.simpleName
val message = "#handleEvent: called for " + event.javaClass.simpleName
Toast.makeText(context, className + message, Toast.LENGTH_SHORT).show()
Log.d(className, message)
}
class SampleEvent
}
(b). BlankFragment.kt
package com.example.eventbuskotlin
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import org.greenrobot.eventbus.Subscribe
class BlankFragment : BlankBaseFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_blank, container, false)
}
@Subscribe // subscribe annotation in base class would not be picked up by index
override fun handleEvent(event: BlankBaseFragment.SampleEvent) {
super.handleEvent(event)
}
class SampleEvent
}
Step 5: Create Activities
We will have two activities:
(a). EmptyActivity.kt
package com.example.eventbuskotlin
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import org.greenrobot.eventbus.EventBus
class EmptyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_empty)
}
fun onPostStickyButtonClick(view: View) {
EventBus.getDefault().postSticky(BlankBaseFragment.SampleEvent())
finish()
}
}
(b). MainActivity.kt
package com.example.eventbuskotlin
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.view.View
import android.widget.Toast
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
}
@Subscribe(sticky = true)
fun handleEvent(event: BlankBaseFragment.SampleEvent) {
val className = this.javaClass.simpleName
val message = "#handleEvent: called for " + event.javaClass.simpleName
Toast.makeText(this, className + message, Toast.LENGTH_SHORT).show()
Log.d(className, message)
// prevent event from re-delivering, like when leaving and coming back to app
EventBus.getDefault().removeStickyEvent(event)
}
fun onPostButtonClick(view: View) {
EventBus.getDefault().post(BlankBaseFragment.SampleEvent())
}
fun onLaunchButtonClick(view: View) {
startActivity(Intent(this, EmptyActivity::class.java))
}
}