eventbus for android
DESCRIPTION
EventBus is an Android optimized publish/subscribe event bus. A typical use case for Android apps is gluing Activities, Fragments, and background threads together.TRANSCRIPT
EventBusfor Android.droidcon NL23.11.2012Markus Junginger
© Copyright 2012 Markus Junginger.All rights reserved.
Android Developerssince 2007.Based in Munich.We are looking for:– Cool Android projects– Android developers(see Jobs)
Follow us:@greenrobot_de
Random Qoutes
„Really easy to use“
„exc
elle
nt h
elp“
“very clean way for c
ommunication”
„Excellent!““I re
moved a lot of b
oiler plate”
„very easy and stra
ightforw
ard“
Status Quo in Android
Q: Who is talking to whom?
Status Quo in Android
Fragment Fragment
Activity
Service / Helper
Thread
Activity
Communication Issues?!
Tight coupling of components Inflexible, changes are expensive
Boiler plate code– Define interfaces– Callbacks for asynch. communication– Listener management– Propagation through all layers
EventBus Communication
Fragment Fragment
Activity
Service / Helper
Thread
Activity
EventBus
EventBus for Android
Event-based Publish/Subscribe Bus: central communication Inspired by Guava‘s EventBus (Google) Android-optimized Open Source, Apache 2 License
https://github.com/greenrobot/EventBus
EventBus in 4 Steps
1. Define an event
2. Register subscriber
3. Post an event
4. Receive the event
EventBus in 4 Steps: Code!
1. Define an eventpublic class MyEvent {}
2. Register subscriberEventBus.getDefault().register(this);
3. Post an eventEventBus.getDefault().post(event);
4. Receive the eventpublic void onEvent(MyEvent event);
Publish / Subscribe
PublisherEventBus
Subscriber
Event
post()
EventonEvent()
Subscriber
Event
onEvent()
EventBus Instances
EventBus instances Instances are indepent from each other For many apps, a single instance is fine „Convenience“ InstanceEventBus.getDefault()
Aquire it anywhere(!) in your code
Event Handler Method: onEvent EventBus scans subscribers
– During (first) registration of subscriber– For event handler methods
Event handler methods– Naming convention: onEvent– public visibility– No return value (void)– Single parameter for the event to receive
Type-based Event Routing
Event type: Java class of the event To receive an event, its type must match post(new MyEvent()); onEvent(MyEvent event) {…}
Type hierarchy of events– Implement logging of all events:
onEvent(Object event)
Event Type is a Filter
PublisherEventBus
Subscriber
Event
post(MyEvent)
EventonEvent(MyEvent)
Subscriber
onEvent(OtherEvent)
CODEIt‘s time to see some
EventBus Code: Sender
MyEvent myEvent = new MyEvent(anyData);EventBus.getDefault().post(myEvent);
EventBus Code: Receiver
MyActivity extends Activity // no interf.
// onCreate or onResumeEventBus.getDefault().register(this);
// onDestroy or onPauseEventBus.getDefault().unregister(this);
public onEvent(MyEvent event) { … }
Example: Fragment to Fragment Tap on one fragment Another fragment reacts Typical list/details scenario Conventional setup:
Activity is managingFragments
Fragment Fragment
Activity
Conventional: DetailFragment
// Here‘s the action. How is it called?public void loadDetails(Item item) { …}
Conventional: ListFragment
interface Contract {void onItemSelected(Item item);
}
// Propagate to Activity((Contract)getActivity()).onItemSelected(item);
Conventional: Activity
public class MyActivity implements ListFragment.Contract {
public void onItemSelected(Item item) { DetailFragment detailFragment = (DetailFragment) getFragmentManager().findFragmentBy…; detailFragment.loadDetails(item); }}
EventBus: Event class
public class ItemSelectedEvent { public final Item item;
public ItemSelectedEvent(Item item) { this.item = item; }}
EventBus: Post & Receive
// In ListFragmentEventBus.getDefault().post(new ItemSelectedEvent(item));
// In DetailFragment (extends EventBusFragment)public void onEvent(ItemSelectedEvent event) {…}
THREADING SUPPORTEvent Delivery in other Threads
Why do Threads matter?
Responsive UI, Android conventions– Main/UI thread must not block– UI updates in the main thread– Networking etc. in background threads
Threads and Events– Thread posting events– Thread handling events– Posting and handling thread may differ
EventBus Threading Support
Event delivery using threads Event handler method decides
(handler knows best what it is doing) Naming conventions for onEvent methods To deliver in the main thread:
onEventMainThread(…) (All methods beginning with onEvent are
checked for typos)
Thread Modes
PostThread: Direct call in same thread MainThread: UI updates etc. BackgroundThread: „not the main
thread“ Async: always asynchronous to posting Used in the method name: onEventXXX No additional code required
Threading Example
Network thread posts resultpost(new UserLoginEvent(name));
Fragment reacts to event in main threadpublic void onEventMainThread(UserLoginEvent e) { textView.setText(e.getName());}
SNEAK PREVIEWAsynchronous execution and error dialogs
Upcoming: EventBus 2.1
EventBus 2.1 is not final yet;Still gathering experience and feedback
Everything pushed to master branch No relevant changes in the core (planned) Comes with some helpers
– AsyncExecutor– Error dialog
EventBus 2.1: AsyncExecutor
A thread pool, but with failure handling RunnableEx interface
– Like Runnable to define code to run async.– May throw any execption
ThrowableFailureEvent– Posted when exception occurs– Throwable object is wrapped inside– Subclass to customize and filter for type
AsyncExecutor: Calling Code
AsyncExecutor.create().execute( new RunnableEx { public void run throws LoginException { remote.login(); EventBus.getDefault().postSticky( new LoggedInEvent()); // No need to catch Exception } }}
AsyncExecutor: Receiving Codepublic voidonEventMainThread(LoggedInEvent event) { // Change some UI}
Comparison to AsyncTask
AsyncExecutor advantages– Don’t worry about configuration changes
(typically device rotation)– Failure handling– EventBus (other dependencies somewhere?)
AsyncTask advantage– Canceling task
EventBus 2.1: Error Dialog
Operations may fail (networking, etc.) Some UI response should be shown
– Currently: error dialogs– Later: Possibly maybe someth. Crouton-ish
Multiple errors: don’t open multiple times Goal: Minimize required code
How Error Dialogs work
Error handling “attaches” to Activities Displaying dialogs is triggered by events ThrowableFailureEvent or subclass
– AsyncExecutor sends those– Or post those events manually
Error Dialogs: Code
// In onCreate in your ActivityErrorDialogManager.attachTo(this);
// Trigger the dialogbus.post(new ThrowableFailureEvent(ex));// Or let AsyncExecutor do it for you…
Dialog Configuration
Which texts to display in the dialog? Simple option: Configure
– Supply default resources for title and text– Map exception types texts
Flexible option: extend ErrorDialogFragmentFactory
Dialog Configuration: Code
// Initialize in your Application classErrorDialogConfig config = new ErrorDialogConfig(getResources(), R.string.error_generalTitle, R.string.error_general);config.addMapping(UnknownHostException.class, R.string.error_noInternetConnection);config.addMapping(IOException.class, R.string.error_generalServer);ErrorDialogManager.factory = new ErrorDialogFragmentFactory.Support(config);
Comparison Android Broadcast Nice, but somewhat inconvenient BroadcastReceiver has to be extended Registration needed for every event type Extra work to filter for desired event types
(IntentFilter with e.g. ACTION String) Data is converted into Intent extras
TIPPS AND SNIPPSTiny bits and some other stuff
Sticky Events
Events can be posted using sticky modepostSticky(event); // Instead of post(…)
The last sticky event is kept in memory Registration with getting sticky eventsregisterSticky(subscriber);
Query for sticky eventgetStickyEvent(Class<?> eventType)
Remove sticky event (Class or Object)removeStickyEvent(Class<?> eventType)
Events Class
Event classes are tiny; group them
public class Events { public static class InitThreadCompleteEvent { }
public static class LoginCompleteEvent { }}
EventBusFragment/-Activity
Superclass depends on your setup Implement in your project
class EventBusFragment extends Fragment { public void onCreate(…) { super.onCreate(…); EventBus.getDefault().register(this); } public void onDestroy() { EventBus.getDefault().unregister(this); super.onDestroy(); }
When to use EventBus
Medium/high distance of components:“Somewhere” else should happen sth.
Potentially multiple dependencies Asynchronous logic When not to use EventBus
– Strictly internal matters:Use methods and interfaces instead
– Inter-process communication
License, Contact
This presentation is licensed under CreativeCommons ShareAlike/Attributionhttp://creativecommons.org/licenses/by-sa/3.0/
Contact greenrobot– http://greenrobot.de – http://twitter.com/greenrobot_de – Google+: http://bit.ly/greenrobotplus