preface
The basic use of EventBus, portal, was described in the previous post: In this article, we’ll explore the fun and advanced uses of EventBus step by step. There are mainly
- Thread Mode
- Configuration
- Sticky Events
- Priorities and Event Cancellation function
- Subscriber Index
- AsyncExecutor
Without further ado, let’s get started
Advanced usage
Thread Mode
Remember from the last article, the information contained in the @Subscribe method
@Subscribe(threadMode = ThreadMode.MAIN)
public void onUpdateUIEvent(UpdateUIEvent updateUIEvent) {
mTextView.setText("There's only one Eason Chan");
Copy the code
Threadmode. MAIN is just one way to determine which thread the subscription method will execute on by specifying threadMode. Take a look at the others
public enum ThreadMode {
/**
* Subscriber will be called in the same thread, which is posting the event. This is the default. Event delivery
* implies the least overhead because it avoids thread switching completely. Thus this is the recommended mode for* simple tasks that are known to complete is a very short time without requiring the main thread. Event handlers * using this mode mustreturn quickly to avoid blocking the posting thread, which may be the main thread.
*/
POSTING,
/**
* Subscriber will be called in Android's main thread (sometimes referred to as UI thread). If the posting thread is * the main thread, event handler methods will be called directly. Event handlers using this mode must return * quickly to avoid blocking the main thread. */ MAIN, /** * Subscriber will be called in a background thread. If posting thread is not the main thread, event handler methods * will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single * background thread, that will deliver all its events sequentially. Event handlers using this mode should try to * return quickly to avoid blocking the background thread. */ BACKGROUND, /** * Event handler methods are called in a separate thread. This is always independent from the posting thread and the * main thread. Posting events never wait for event handler methods using this mode. Event handler methods should * use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number * of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus * uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications. */ ASYNC }Copy the code
At a glance, the notes summarize the application scenarios of the four modes
- POSTING: Events are posted on the same thread as subscribed.
- MAIN: Events are subscribed to in the MAIN thread regardless of which thread they are published in.
- BACKGROUND: Subscribes to the thread if it is not the main thread, or to a separate BACKGROUND thread if it is the main thread.
- ASYNC: Subscribes with thread pool threads.
Such as
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onUpdateUIEvent(UpdateUIEvent updateUIEvent) {
mTextView.setText("There's only one Eason Chan");
}
Copy the code
We then subscribe to events in the background, but since UI updates are only in the main thread, the following exception occurs
Could not dispatch event: class com.charmingwong.androidtest.UpdateUIEvent to subscribing class class com.charmingwong.androidtest.MainActivity
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Copy the code
Configuration
The default way to get an EventBus instance is
EventBus.getDefault().register(this);
Copy the code
In this way, the attributes of EventBus are obtained by default, which sometimes does not meet our requirements. In this case, we can use EventBusBuilder to configure EventBus attributes
EventBus eventBus = EventBus.builder().eventInheritance(true)
.ignoreGeneratedIndex(false)
.logNoSubscriberMessages(true)
.logSubscriberExceptions(false)
.sendNoSubscriberEvent(true)
.sendSubscriberExceptionEvent(true)
.throwSubscriberException(true)
.strictMethodVerification(true)
.build();
eventBus.register(this);
Copy the code
Builder () returns EventBusBuilder ()
// Create a default EventBus object, equivalent to eventbus.getDefault (). EventBus installDefaultEventBus() : // Add the index generated by the EventBus "annotation preprocessor EventBuilder addIndex(SubscriberInfoIndex index) : // By default, EventBus assumes that the event class has a hierarchy (the subscriber superclass will be notified) / / define a thread pool is used for processing the background thread and asynchronous thread distribute events EventBuilder executorService (Java. Util. Concurrent. The executorService executorService) : // Sets the subscription index to be ignored, even if the event is indexed. Default isfalseEventBuilder ignoreGeneratedIndex(Boolean ignoreGeneratedIndex) : // Prints no subscription message, default istrue
EventBuilder logNoSubscriberMessages(boolean logNoSubscriberMessages) : // Print subscription exception, defaulttrue
EventBuilder logSubscriberExceptions(boolean log// Sets whether EventBus will remain silent when events are sent without subscribers. DefaulttrueEventBuilder sendNoSubscriberEvent(Boolean sendNoSubscriberEvent) : // An exception sent to distribute events. DefaulttrueEventBuilder sendSubscriberExceptionEvent (Boolean sendSubscriberExceptionEvent) : Before 3.0, the method name that receives a processing event starts with onEvent. Avoid method name validation that does not start with onEvent. Enable strict method validation (default:false) EventBuilder strictMethodVerification (Java. Lang. Class <? > clazz) // If an exception occurs in the onEvent*** method, whether to distribute this exception to subscribers (default:false(Boolean) EventBuilder throwSubscriberException throwSubscriberException)Copy the code
In this way, we have the flexibility to use EventBus.
Sticky Events
After a sticky event is published, subsequent subscribers can no longer receive it. After a Sticky event is published, EventBus will save it until a new sticky event of the same type is published, and then the old one will be overwritten. Therefore, subsequent subscribers can only use sticky mode. You can still get the sticky event. The usage is as follows:
Subscribe to the sticky event in SecondActivity and register
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // Register the page as a subscriber eventbus.getDefault ().register(this); } @Subscribe(sticky =true)
public void onMyStickyEvent(MyStickyEvent myStickyEvent) {
mTextView.setText("Someone asked you if he was Eason Chan.");
}
Copy the code
Publish events in MainActivity
@override public void onClick(View v) {eventBus.getDefault ().poststicky (new MyStickyEvent()); Intent intent = new Intent(MainActivity.this, SecondActivity.class); startActivity(intent); }Copy the code
Take a look at the results:
Before MainActivity starts, publish the sticky event, and then SecondActivity starts again. After registering as a subscriber, the user can still receive the sticky event. The success proves the function of sticky and also verifies the above statement. After the sticky event is published, it can also be removed
MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent ! = null) { // Nowdo something with it
}
Copy the code
Priorities and Event Cancellation
Here is an example to verify the priority relationship
// MainActivity
@Subscribe(priority = 2)
public void onUpdateUIEvent(UpdateUIEvent updateUIEvent) {
Log.d(TAG, "onUpdateUIEvent: priority = 2");
}
// SecondActivity
@Subscribe(priority = 1)
public void onUpdateUIEvent(UpdateUIEvent updateUIEvent) {
Log.d(TAG, "onUpdateUIEvent: priority = 1");
}
Copy the code
Both activities subscribe to the same event type, but with different priorities, and publish events in SecondActivity
Eventbus.getdefault ().post(new UpdateUIEvent());Copy the code
To see the running effect, log:
D/MainActivity: onUpdateUIEvent: priority = 2
D/SecondActivity: onUpdateUIEvent: priority = 1
Copy the code
Switch priorities again
// MainActivity
@Subscribe(priority = 1)
public void onUpdateUIEvent(UpdateUIEvent updateUIEvent) {
Log.d(TAG, "onUpdateUIEvent: priority = 1");
}
// SecondActivity
@Subscribe(priority = 2)
public void onUpdateUIEvent(UpdateUIEvent updateUIEvent) {
Log.d(TAG, "onUpdateUIEvent: priority = 2");
}
Copy the code
Run, see log:
D/SecondActivity: onUpdateUIEvent: priority = 2
D/MainActivity: onUpdateUIEvent: priority = 1
Copy the code
Priority determines the order in which events are received. The higher the priority is, the earlier the events are received. The subscriber that receives the event first can also intercept the event and cancel further delivery, and subsequent lower-priority subscribers will not receive the event again. We can set the cancel event to continue delivery like this:
@Subscribe(priority = 2)
public void onUpdateUIEvent(UpdateUIEvent updateUIEvent) {
Log.d(TAG, "onUpdateUIEvent: priority = 2");
EventBus.getDefault().cancelEventDelivery(updateUIEvent);
}
Copy the code
Run, see log:
D/SecondActivity: onUpdateUIEvent: priority = 2
Copy the code
Sure enough, the subscriber with Priority =1 did not receive the event, which is EventBus’s ability to cancel the event and continue delivery.
Subscriber Index
After reading the official document, we know that Subscriber Index is a new technology on EventBus 3, so it is also suggested that those who have not learned EventBus can skip the version before 2.x and directly learn the latest version. About the characteristics of The Subscriber Index technology of EventBus, please translate the official explanation:
It is an optional optimization to speed up initial subscriber registration.
Subscriber Index is an optional optimization technique to speed up initial Subscriber registration.
The subscriber index can be created during build time using the EventBus annotation processor. While it is not required to use an index, it is recommended on Android for best performance.
The Subscriber Index is created at compile time using the EventBus annotation processor, and while it is not mandatory, it is officially recommended as it has the best performance on Android.
How to use: In Gradle do the following configuration
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [ eventBusIndex : 'com.example.myapp.MyEventBusIndex' ]
}
}
}
}
dependencies {
compile 'org. Greenrobot: eventbus: 3.1.1'
annotationProcessor 'org. Greenrobot: eventbus -- the annotation processor: 3.1.1'
}
Copy the code
If the above method does not work, you can also use the Android-apt Gradle plugin
buildscript {
dependencies {
classpath 'com. Neenbedankt. Gradle. Plugins: android - apt: 1.8'
}
}
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
compile 'org. Greenrobot: eventbus: 3.1.1'
apt 'org. Greenrobot: eventbus -- the annotation processor: 3.1.1'
}
apt {
arguments {
eventBusIndex "com.example.myapp.MyEventBusIndex"}}Copy the code
Once configured, we can add indexes to our code
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
// Now the default instance uses the given index. Use it like this:
EventBus eventBus = EventBus.getDefault();
Copy the code
In addition to Application, you can also use indexes in the Library
EventBus eventBus = EventBus.builder()
.addIndex(new MyEventBusAppIndex())
.addIndex(new MyEventBusLibIndex()).build();
Copy the code
Ok, so that’s how indexes are used.
AsyncExecutor
Let’s look at an example
AsyncExecutor.create().execute(
new AsyncExecutor.RunnableEx() { @Override public void run() throws Exception { // No need to catch any Exception (here: LoginException) prepare(); EventBus.getDefault().postSticky(new MyStickyEvent()); }}); private void prepare() throws Exception { throw new Exception("prepare failed");
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onUpdateUIEvent(UpdateUIEvent updateUIEvent) {
Log.d(TAG, "onUpdateUIEvent: ");
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void handleFailureEvent(ThrowableFailureEvent event) {
Log.d(TAG, "handleFailureEvent: " + event.getThrowable().getMessage());
Copy the code
In this way, if an exception occurs in the relevant code, the exception is encapsulated as a ThrowableFailureEvent, which is automatically published. Once the subscriber defines a method to receive the ThrowableFailureEvent, the exception information is available. Subsequent Update euievent will not be published, and if no exception occurs, the normal publishing event will occur. Run, see log:
D/SecondActivity: handleFailureEvent: prepare failed
Copy the code
Sure enough, only handleFailureEvent(ThrowableFailureEvent) received an exception event. The advantage of this approach is that the exception information can be handed to the subscriber, who can deal with it accordingly.
conclusion
There are a few other features of EventBus that you can see in the official documentation. If you don’t understand something, it’s important to check the official documentation.
Poke me, read EventBus official documentation!
The next article focuses on the source code for EventBus and how it works.