15
15
*/
16
16
package de .greenrobot .event ;
17
17
18
+ import android .os .Looper ;
19
+ import android .util .Log ;
20
+
18
21
import java .lang .reflect .InvocationTargetException ;
19
22
import java .util .ArrayList ;
20
23
import java .util .HashMap ;
23
26
import java .util .concurrent .ConcurrentHashMap ;
24
27
import java .util .concurrent .CopyOnWriteArrayList ;
25
28
import java .util .concurrent .ExecutorService ;
26
- import java .util .concurrent .Executors ;
27
-
28
- import android .os .Looper ;
29
- import android .util .Log ;
30
29
31
30
/**
32
- * EventBus is a central publish/subscribe event system for Android. Events are posted ({@link #post(Object)} to the
33
- * bus, which delivers it to subscribers that have matching handler methods for the event type. To receive events,
34
- * subscribers must register themselves to the bus using the {@link #register(Object)} method . Once registered,
35
- * subscribers receive events until the call of {@link #unregister(Object)}. By convention, event handling methods must
31
+ * EventBus is a central publish/subscribe event system for Android. Events are posted ({@link #post(Object)}) to the
32
+ * bus, which delivers it to subscribers that have a matching handler method for the event type. To receive events,
33
+ * subscribers must register themselves to the bus using {@link #register(Object)}. Once registered,
34
+ * subscribers receive events until {@link #unregister(Object)} is called . By convention, event handling methods must
36
35
* be named "onEvent", be public, return nothing (void), and have exactly one parameter (the event).
37
36
*
38
37
* @author Markus Junginger, greenrobot
39
38
*/
40
39
public class EventBus {
41
- static ExecutorService executorService = Executors .newCachedThreadPool ();
42
40
43
41
/** Log tag, apps may override it. */
44
42
public static String TAG = "Event" ;
45
43
46
- private static volatile EventBus defaultInstance ;
44
+ static volatile EventBus defaultInstance ;
47
45
46
+ private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder ();
48
47
private static final String DEFAULT_METHOD_NAME = "onEvent" ;
49
48
private static final Map <Class <?>, List <Class <?>>> eventTypesCache = new HashMap <Class <?>, List <Class <?>>>();
50
49
@@ -64,10 +63,13 @@ protected PostingThreadState initialValue() {
64
63
private final BackgroundPoster backgroundPoster ;
65
64
private final AsyncPoster asyncPoster ;
66
65
private final SubscriberMethodFinder subscriberMethodFinder ;
66
+ private final ExecutorService executorService ;
67
67
68
- private boolean subscribed ;
69
- private boolean logSubscriberExceptions ;
70
- private boolean logNoSubscriberMessages ;
68
+ private final boolean failFast ;
69
+ private final boolean logSubscriberExceptions ;
70
+ private final boolean logNoSubscriberMessages ;
71
+ private final boolean sendSubscriberExceptionEvent ;
72
+ private final boolean sendNoSubscriberEvent ;
71
73
72
74
/** Convenience singleton for apps using a process-wide EventBus instance. */
73
75
public static EventBus getDefault () {
@@ -81,65 +83,40 @@ public static EventBus getDefault() {
81
83
return defaultInstance ;
82
84
}
83
85
86
+ public static EventBusBuilder builder () {
87
+ return new EventBusBuilder ();
88
+ }
89
+
84
90
/** For unit test primarily. */
85
91
public static void clearCaches () {
86
92
SubscriberMethodFinder .clearCaches ();
87
93
eventTypesCache .clear ();
88
94
}
89
95
90
- /**
91
- * Method name verification is done for methods starting with onEvent to avoid typos; using this method you can
92
- * exclude subscriber classes from this check. Also disables checks for method modifiers (public, not static nor
93
- * abstract).
94
- */
95
- public static void skipMethodVerificationFor (Class <?> clazz ) {
96
- SubscriberMethodFinder .skipMethodVerificationFor (clazz );
97
- }
98
-
99
- /** For unit test primarily. */
100
- public static void clearSkipMethodNameVerifications () {
101
- SubscriberMethodFinder .clearSkipMethodVerifications ();
102
- }
103
-
104
96
/**
105
97
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
106
98
* central bus, consider {@link #getDefault()}.
107
99
*/
108
100
public EventBus () {
101
+ this (DEFAULT_BUILDER );
102
+ }
103
+
104
+ EventBus (EventBusBuilder builder ) {
109
105
subscriptionsByEventType = new HashMap <Class <?>, CopyOnWriteArrayList <Subscription >>();
110
106
typesBySubscriber = new HashMap <Object , List <Class <?>>>();
111
107
stickyEvents = new ConcurrentHashMap <Class <?>, Object >();
112
108
mainThreadPoster = new HandlerPoster (this , Looper .getMainLooper (), 10 );
113
109
backgroundPoster = new BackgroundPoster (this );
114
110
asyncPoster = new AsyncPoster (this );
115
- subscriberMethodFinder = new SubscriberMethodFinder ();
116
- logSubscriberExceptions = true ;
117
- logNoSubscriberMessages = true ;
111
+ subscriberMethodFinder = new SubscriberMethodFinder (builder .skipMethodVerificationForClasses );
112
+ logSubscriberExceptions = builder .logSubscriberExceptions ;
113
+ logNoSubscriberMessages = builder .logNoSubscriberMessages ;
114
+ sendSubscriberExceptionEvent = builder .sendSubscriberExceptionEvent ;
115
+ sendNoSubscriberEvent = builder .sendNoSubscriberEvent ;
116
+ failFast = builder .failFast ;
117
+ executorService = builder .executorService ;
118
118
}
119
119
120
- /**
121
- * Before registering any subscribers, use this method to configure if EventBus should log exceptions thrown by
122
- * subscribers (default: true).
123
- */
124
- public void configureLogSubscriberExceptions (boolean logSubscriberExceptions ) {
125
- checkConfigurationAllowed ();
126
- this .logSubscriberExceptions = logSubscriberExceptions ;
127
- }
128
-
129
- /**
130
- * Configure if EventBus should log "No subscribers registered for event" messages (default: true).
131
- */
132
- public void configureLogNoSubscriberMessages (boolean logNoSubscriberMessages ) {
133
- checkConfigurationAllowed ();
134
- this .logNoSubscriberMessages = logNoSubscriberMessages ;
135
- }
136
-
137
- // TODO maybe we should switch to a builder pattern to avoid this
138
- private void checkConfigurationAllowed () throws EventBusException {
139
- if (subscribed ) {
140
- throw new EventBusException ("This method must be called before any registration" );
141
- }
142
- }
143
120
144
121
/**
145
122
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
@@ -258,7 +235,6 @@ private synchronized void register(Object subscriber, String methodName, boolean
258
235
259
236
// Must be called in synchronized block
260
237
private void subscribe (Object subscriber , SubscriberMethod subscriberMethod , boolean sticky , int priority ) {
261
- subscribed = true ;
262
238
Class <?> eventType = subscriberMethod .eventType ;
263
239
CopyOnWriteArrayList <Subscription > subscriptions = subscriptionsByEventType .get (eventType );
264
240
Subscription newSubscription = new Subscription (subscriber , subscriberMethod , priority );
@@ -502,7 +478,8 @@ private void postSingleEvent(Object event, PostingThreadState postingState) thro
502
478
if (logNoSubscriberMessages ) {
503
479
Log .d (TAG , "No subscribers registered for event " + eventClass );
504
480
}
505
- if (eventClass != NoSubscriberEvent .class && eventClass != SubscriberExceptionEvent .class ) {
481
+ if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent .class &&
482
+ eventClass != SubscriberExceptionEvent .class ) {
506
483
post (new NoSubscriberEvent (this , event ));
507
484
}
508
485
}
@@ -578,7 +555,7 @@ void invokeSubscriber(PendingPost pendingPost) {
578
555
}
579
556
}
580
557
581
- void invokeSubscriber (Subscription subscription , Object event ) throws Error {
558
+ void invokeSubscriber (Subscription subscription , Object event ) {
582
559
try {
583
560
subscription .subscriberMethod .method .invoke (subscription .subscriber , event );
584
561
} catch (InvocationTargetException e ) {
@@ -591,13 +568,18 @@ void invokeSubscriber(Subscription subscription, Object event) throws Error {
591
568
Log .e (TAG , "Initial event " + exEvent .causingEvent + " caused exception in "
592
569
+ exEvent .causingSubscriber , exEvent .throwable );
593
570
} else {
571
+ if (failFast ) {
572
+ throw new EventBusException ("Invoking subscriber failed" , cause );
573
+ }
594
574
if (logSubscriberExceptions ) {
595
575
Log .e (TAG , "Could not dispatch event: " + event .getClass () + " to subscribing class "
596
576
+ subscription .subscriber .getClass (), cause );
597
577
}
598
- SubscriberExceptionEvent exEvent = new SubscriberExceptionEvent (this , cause , event ,
599
- subscription .subscriber );
600
- post (exEvent );
578
+ if (sendSubscriberExceptionEvent ) {
579
+ SubscriberExceptionEvent exEvent = new SubscriberExceptionEvent (this , cause , event ,
580
+ subscription .subscriber );
581
+ post (exEvent );
582
+ }
601
583
}
602
584
} catch (IllegalAccessException e ) {
603
585
throw new IllegalStateException ("Unexpected exception" , e );
@@ -614,6 +596,10 @@ final static class PostingThreadState {
614
596
boolean canceled ;
615
597
}
616
598
599
+ ExecutorService getExecutorService () {
600
+ return executorService ;
601
+ }
602
+
617
603
// Just an idea: we could provide a callback to post() to be notified, an alternative would be events, of course...
618
604
/* public */ interface PostCallback {
619
605
void onPostCompleted (List <SubscriberExceptionEvent > exceptionEvents );
0 commit comments