Integration with Otto

Otto is a well known library from Square. I recently integrated with Otto into my Android project – the integration was painless. The following blog post illustrates how the code changed for activity-fragment communication, before and after integration with Otto. Also dont miss reading the “Things to Watch out for” section at the bottom of this post.

Before Otto Integration:

MainActivity interacts with and controls (say) 3 fragments.

MainActivity needs to ‘listen’ to (Say) 4 events from these 3 fragments, mainly for coordination amongst fragments. Each fragment then defines an interface that the MainActivity implements. Sample code for Fragment A shows here.

FragmentA code – before Otto:

public class FragmentA extends BaseFragment {

        /* First, define a private member to register callbacks. */

        private IActionACallBack actionACallback = null;

        /* Define an interface that the Activity can implement */

        public interface IActionACallBack() {

            public void actOnActionA();

        }

        /* register the activity with this fragment */

        public void setActionAListener(IActionACallBack callback)  {

            actionACallback = callback;  

        }

        /* When the activity needs to be notified, typically when the fragment is done with its part, call-back the activity that was previously registered with this fragment */

        private void onSomeEventOrWhenFragmentIsDone() {

            actionACallback.actOnActionA();

        }

} // end FragmentA

MainActivity code – before Otto:

public class MainActivity extends BaseActivity implements FragmentA.IActionACallBack, FragmentB.IActionBCallBack, FragmentC.IActionCCallBack {

            // activity code.

            @Override

            public void actOnActionA() {

                    // switch fragments here – maybe display Fragment B    

            }            

        }

} // end MainActivity

Obviously, apart from code bloat in the form of multiple interfaces and callback implementations, the other downside to the above design is the multiple interfaces that the activity needs to implement, which leads to tight-coupling between the activity and the fragment(s). Integration with Otto eliminates this tight-coupling by making activity-fragment communication event based through the Otto bus. Fragments can post events which Activities can subscribe to via the bus. Activities then don’t have to implement multiple interfaces defined within fragments.

After Otto Integration: The following lines of code shows the design after integration with Otto.

FragmentA code – after Otto:

public class FragmentA extends BaseFragment {

        // inject a busprovider object via guice

        @Inject private BusProvider busProvider; // busprovider implementation follows

        // communicate with the activity by posting an interesting event to the bus. This event object (FragmentAInterestingEvent) can take a optional parameter (obj), depending on the business case.

        private void notifyListeners() {

            busProvider.get().post(new FragmentAInterestingEvent(obj));

        }

}

MainActivity code – after Otto:

public class MainActivity extends BaseActivity { // note: NO interface implementations here!

        // Define all the events that the activity is interested in, within the eventhandler object below. If your app has base and derived classes that need to listen to the same subscribed events, avoid writing subscribe methods in both base and derived classes (original eventhandler implementation here)

        private final Object eventhandler = new Object() {
                @Subscribe
                public void FragmentAInterestingEvent(final FragmentAInterestingEvent event) {
                    doSomething();
                    return;
                }

                @Subscribe
                public void FragmentBInterestingEvent(final FragmentBInterestingEvent event) {
                    doSomethingElse();
                    return;
                }        }  // end eventhandler

        // register eventhandler in onResume
        public void onResume() {
                    super.OnResume();
                    busProvider.get().register(eventhandler);
        }

        // un-register eventhandler in onPause
        public void onPause() {
                    super.onPause();
                    busProvider.get().unregister(eventhandler);
        }    

} // end MainActivity

// BusProvider Implementation
public class BusProvider implements Provider<Bus> {
        Bus eventbus = null;    

        @Override
        public Bus get() {
            if (eventbus == null) {
                eventbus = new Bus(ThreadEnforcer.ANY); // receive callback on any thread, not just the main thread
            }
            return eventbus;
        }
}

Things to Watch out for:

1. One common issue faced while using Otto for the first time is that the @Subscribe method does not get called. The most common reason for this is that the busprovider object is not the same across different activities. Make sure the the busprovider is a singleton instance across your app. One way is to specify the binding using Guice:

        bind(BusProvider.class).in(Scopes.SINGLETON);

2. Classes that only post events don’t need to register and un-register with the bus.

3. If you use the @Producer annotation (not covered in the above post), make sure to do the initial state handling. Producers provide an ‘immediate’ callback to their subscribers (not just when you expect them to, as on a user event that you have coded up) and its easy to miss the initial state handling.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s