Home Tutorials Training Consulting Books Company Contact us


Get more...

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