Using the Otto event bus in Android applications. This tutorial explains the usage of the Otto event bus library.
1. Otto as event bus system
1.1. Otto as event bus system
Otto is an open source project providing an event bus implementation. Components can publish and subscribe to events.
Otto has been a fork of the Guava event bus library from Google and been redesigned to support Android as well as possible. Unlike the Guava event bus, Otto does not consider event subscriptions from base classes or interface. This is done to improve performance of the library and to keep the application code simple and unambiguous.
1.2. Installation
If you are using Maven or Gradle as build system you can simply add a dependency to it.
dependencies {
compile 'com.squareup:otto:1.3.8'
}
<dependency>
<groupId>com.squareup</groupId>
<artifactId>otto</artifactId>
<version>1.3.8</version>
</dependency>
You could also download the JAR manually from Download Otto and add it to the classpath of your application.
1.3. When to use Otto?
Otto can be used to communicate between your activity and fragments or to communicate between an activity and a service.
An alternative solution would be the usage of RxJava. See Implementing an Event Bus With RxJava blog post for an example. |
1.4. How to setup Otto?
The following description assumes you are using Otto in an Android application, even though it is possible to use it in an standard Java application. |
To use Otto, create a singleton instance of the Bus
class and provide access to it for your Android components.
This is typically done in the Application
object of your Android application.
public static Bus bus = new Bus(ThreadEnforcer.MAIN);
In this example the ThreadEnforcer.MAIN
parameter is used,.
This enforces Otto to send events always from the main thread.
If you want to be able to send events from any thread use the ThreadEnforcer.ANY
parameter.
1.5. How to register and unregister for events?
Event registration is done via the @Subcribe
annotation on a public single parameter method.
The method parameter is the event key, i.e., if such an data type is send via the Otto event bus the method is called.
Event receivers must register via the register
method of the Bus
class.
// subscribe for string messages
@Subscribe
public void getMessage(String s) {
Toast.makeText(this, s, Toast.LENGTH_LONG).show();
}
//subscribe for TestData messages
@Subscribe
public void getMessage(TestData data) {
Toast.makeText(getActivity(), data.message, Toast.LENGTH_LONG).show();
}
//requires a registration e.g. in the onCreate method
bus.register(this);
To unregister from events use the unregister()
method.
1.6. How to send events
For sending events it is not necessary to register with the event bus.
Simple call the post() method of the `Bus
class.
// post a string object
bus.post("Hello");
// example data to post
public class TestData {
public String message;
}
// post this data
bus.post(new TestData().message="Hello from the activity");
1.7. How can new components receive the last event?
Sometimes new components, like a dynamically created fragment, should receive event data during their creation.
If this case component can register as producer for such event data with the @Produce
annotation.
Event receivers must register via the register
method of the Bus
class.
@Produce
public String produceEvent() {
return "Starting up";
}
2. Exercise: Using Otto the event bus system
This is an example for the usage of Otto in an Android application.
Create a new Android project with com.vogella.android.otto
as top level package name based on the Empty Activity
template.
Add the dependency to the build.gradle
file.
dependencies {
// more stuff
implementation 'com.squareup:otto:1.3.8'
// more stuff
}
The activity_main.xml
layout file of the activity should look like the following.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.vogella.android.otto.MainActivity"
tools:ignore="MergeRootFrame" />
The fragment_main.xml
layout file of the fragment should look like the following.
<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">
<Button
android:id="@+id/fragmentbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="Send event from fragment" />
</RelativeLayout>
In this exercise, you use the options menu in the ActionBar
to send a message from the Activity to the Fragment.
To do so, add a menu xml file called menu_main.xml
to your menu resource folder.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_message"
android:title="Send Message"
android:showAsAction="never"/>
</menu>
Add an fragment and add it dynamically to your activity.
Send an event from the fragment to the activity and vice versa.
Display in both case a Toast
.
package com.vogella.android.otto;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.squareup.otto.Bus;
import com.squareup.otto.Produce;
import com.squareup.otto.Subscribe;
import com.squareup.otto.ThreadEnforcer;
public class MainActivity extends Activity {
public static Bus bus;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction().add(R.id.container, new PlaceholderFragment()).commit();
}
bus = new Bus(ThreadEnforcer.MAIN);
bus.register(this);
}
@Subscribe
public void getMessage(String s) {
Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_message) {
bus.post("Hello from the Activity");
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
View button = rootView.findViewById(R.id.fragmentbutton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bus.post("Hello from the Fragment");
}
});
bus.register(this);
return rootView;
}
@Subscribe
public void getMessage(String message) {
Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
}
}
@Produce
public String produceEvent() {
return "Starting up";
}
}
The example is intentional simple.
In a real Android application you would created the Bus singleton in the Application class.
|
3. OkHttp resources
3.1. vogella Java example code
If you need more assistance we offer Online Training and Onsite training as well as consulting