How can I use the Android event bus?
How can I use the Android event bus?
As the name suggests, AndroidEventBus (github link. For more information about why I want to write this database, see AndroidEventBus (Design and Implementation of event Bus). It is an event bus framework of the Android platform, it simplifies the interaction between activities, Fragment, services, and other components, greatly reducing the coupling between them, making our code more concise and less coupled, this improves the quality of our code. But what it can do is not limited to this. After customization, it can complete many interesting functions. What should I do? Let's take a look.
Unbearable pain points
First, let's take A look at this scenario: Have you ever jumped from Activity-A to Activity-B during development, then, A function in Activity-A needs to be called back after Activity-B completes some work. But the Activity cannot manually create an object to set A Listener? Or you may encounter interactions between components such as updating the Activity or Fragment interface in a Service ......
Once you think about it, you will find that interaction between activities, Fragment, and services in Android is quite troublesome. Maybe we first think of using broadcast receivers to interact between them. As mentioned above, send A broadcast in Activity-B and register A broadcast receiver in Activity-A to receive the broadcast. However, it is a little complicated to use a broadcast receiver. If you want to pass an object class as data between components, the object class must implement a serialization interface, which is a little expensive! As shown in Code 1.
Class ActivityA extends Activity {@ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); // register the broadcast receiver registerReceiver (new BroadcastReceiver () {@ Override public void onReceive (Context context, Intent intent) {User person = intent. getParcelableExtra ("user") ;}}, new IntentFilter ("my_action "));}//......} // publish broadcast class ActivityB extends Activity {@ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); // publish broadcast Intent intent = new Intent ("my _ action"); intent. putExtra ("user", new User ("mr. simple "); sendBroadcast (intent );}//......} // The entity class needs to be serialized class User implements Parcelable {String name; public User (String aName) {name = aName;} // Code omitted @ Override public void writeToParcel (Parcel dest, int flags) {dest. writeString (name );}}
Code 1
Is it troublesome? Let's look at another example. during the development process, we often need to perform some time-consuming operations in the Child thread, and then update the results to the UI thread, except AsyncTask, thread and Handler are often used. As shown in Code 2.
class MyActivity extends Activity { Handler mHandler = new Handler () { public void handleMessage(android.os.Message msg) { if ( msg.what == 1 ) { User user = (User)msg.obj ; // do sth } }; } ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // code ...... new Thread( new Runnable() { public void run() { // do sth User newUser = new User("simple") ; Message msg = mHandler.obtainMessage() ; msg.what = 1 ; msg.obj = newUser ; mHandler.sendMessage(msg) ; } }).start(); } }
Code 2
Is it still quite troublesome? Of course, you can also use AsyncTask to simplify the operation. However, several generic parameters of AsyncTask make your code look less concise, therefore, the open source libraries TinyTask and SimpleTask are available on GitHub to simplify the use of AsyncTask. These can be well solved by using AndroidEventBus!
Let's take a look at the strong charm of AndroidEventBus.
AndroidEventBus
There are only three steps to use AndroidEventBus:
Register the object to AndroidEventBus. Use @ Subcriber to mark the subscription function (only one parameter is allowed). Use the post function to publish events.
The corresponding Simple Sequence diagram is as follows:
Created with Rapha? L 2.1.2 EventBus EventBus Subscription object Subscription object Register Release events Query subscription objects The subscription method is executed in a specific thread model. Subscribe execution Method Register a subscription object
Register the subscription object, as shown in code 3.
Public class MainActivity extends Activity {@ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); // registers the object to the event bus. ****** note that you must log out of the event bus in onDestory ***** EventBus. getDefault (). register (this) ;}@ Override protected void onDestroy () {super. onDestroy (); // ****** do not forget to log out ***** EventBus. getDefault (). unregister (this);} // Code omitted}
Code 3
After registering in onCreate, MainActivity can add a subscription function to receive messages. It should be noted that MainActivity needs to be deregistered from the event bus in onDestory. With AndroidEventBus, you can remove callbacks from components such as Activity, Fragment, and Service, reducing coupling and simplifying code.
Event subscription function
The @ Subscriber annotation must be used for event subscription, and the parameter of the subscription function must be one. The event bus identifies the uniqueness of the subscription function based on the parameter type and the tag value of the @ Subscriber annotation. When a user publishes an event, the bus library searches for subscription functions that meet the requirements based on the event type and tag, and runs these subscription functions in the corresponding thread. Let's take a look at the subscription function example in code 4.
Public class MainActivity extends Activity {// Code omitted @ Subcriber (tag = "csuicide") private void csuicideMyself (String msg) {// do Something finish ();} @ Subcriber (mode = ThreadMode. MAIN) private void toastMsgFromEvent (String msg) {// do something} @ Subcriber (tag = "async", mode = ThreadMode. ASYNC) private void executeAsync (final String msg) {// do something} // Code omitted}
Code 4
In code 4, we added the following three subscription functions for MainActivity:
CsuicideMyself: This subscribe function is executed in the main thread. The type of event received is String, and the tag is csuicide. This method is triggered when you publish an event of the String type and the tag is csuicide. ToastMsgFromEvent: The subscription function is also executed in the main thread. The event type is String and the tag is the default value. This method is triggered when the user publishes an event of the String type and the tag is the default event. ExecuteAsync: The subscription function is also executed in an asynchronous thread. The event type is String and the tag is async. This method is triggered when you publish an event of the String type and the tag is async.
From the above description, we can know that the event receiving function has two constraints: the event type and tag (similar to the Action in Intent ). The tag is added because when the event type is the same, if a message is shipped, the event type (such as String) is used as the shipping basis, the subscription function with multiple parameters of String will be triggered, which greatly reduces the flexibility. Release events
// Parameter 1 is of the event type and does not contain tagEventBus. getDefault (). post ("this is an event executed in an asynchronous thread"); // parameter 1 is the event type, parameter 2 is the tag, tag type is the String, similar to the Intent ActionEventBus. getDefault (). post ("this is an event executed in an asynchronous thread", "async ");
An event of any type can be constructed when an event is published. If no tag exists, this parameter can be omitted. After an event is published, AndroidEventBus searches for subscription functions that meet the requirements based on the event type and tag to the registered subscription object. For example, the second event type to be shipped is String and the tag is async, the subscription function that meets the requirements in MainActivity is:
@Subcriber(tag = "async", mode = ThreadMode.ASYNC) private void executeAsync(final String msg) { // do sth }
ThreadMode of AndroidEventBus
In the above Code, there is a piece of code like this:
@Subcriber(mode = ThreadMode.MAIN) private void toastMsgFromEvent(String msg) { }
This mode has a large header. It specifies the thread in which the event receives the function execution. The following three options are available:
ThreadMode. MAIN, the event receiving function is executed in the UI thread; ThreadMode. POST: the thread in which the event is published, and the thread where the receiving function is executed; ThreadMode. ASYNC, the event is executed in an independent asynchronous thread.
In Figure 1, the event receiving function is executed in an asynchronous thread. Through these thread models, we can customize the execution thread of the receiving function. In this way, we can use AndroidEventBus to do a lot of things. For example, to publish an event, perform time-consuming operations in the event receiving Letter, download images, perform HTTP requests, perform I/O operations, and replace components such as Thread and AsyncTask. However, the functions of AndroidEventBus are far more than that. Let's take a look at how to perform higher-end operations.
Figure 1 receiving function execution in asynchronous thread
What else can I do? Alternative application exit implementation
In Android Application Development, in some cases, you can exit the program directly. However, the problem is that the rollback stack contains other activities and the return key cannot be used directly to exit the application. In this case, we usually define another Application subclass, maintain an Activity list in the subclass, and add the Activity to the list when entering the Activity, remove yourself from the Application subclass list before the Activity is destroyed. When exiting the Application, traverse the Activity list of the Application subclass and call the finish function of each Activity. Let's see how AndroidEventBus implements this function. As shown in code 5.
Public class CsuicideActivity extends Activity {@ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); // registers an object to the event bus. ******* you must log out of the event bus in onDestory ***** EventBus. getDefault (). register (this) ;}@ Override protected void onDestroy () {super. onDestroy (); // ****** do not forget to log out ***** EventBus. getDefault (). unregister (this) ;}@ Subcriber (tag = "csuicide") private void csuicideMyself (String msg) {finish ();}}
Code 5
In code 5, we define a CsuicideActivity to register this Activity object in onCreate, log out in onDestroy, and add a subscribe function of csuicideMyself. All Activity classes can inherit from CsuicideActivity. To exit the application, directly publish an event of the String type and csuicide tag type. In this way, all the activities will trigger csuicideMyself, and the function calls the finish method. Therefore, all the activities will exit. In this way, the application exits.
Custom Event processor (EventHandler)
AndroidEventBus was designed with extensibility taken into account at the beginning. The main extension is to subscribe to the function's search policy. Specifically, you can call EventBus. getDefualt (). setMatchPolicy (MatchPolicy policy) to replace the policy. Another important extension is the event processor EventHandler. You can use the setter function to set three event processors. See Code 6.
/*** Set the event processor for execution in the UI thread * @ param handler UI thread event processor */public void setUIThreadEventHandler (EventHandler handler) {mDispatcher. mUIThreadEventHandler = handler;}/*** sets the thread in which the event processor * @ param handler event is delivered, the thread in which the event is executed */public void setPostThreadHandler (EventHandler handler) {mDispatcher. mPostThreadHandler = handler;}/*** sets the event processor for execution in the asynchronous thread * @ param handler asynchronous thread event processor */public void setAsyncEventHandler (EventHandler handler) {mDispatcher. mAsyncEventHandler = handler ;}
Code 6
The EventHandler interface definition is shown in code 7. You only need to implement handleEvent and inject the implementation into EventBus.
/*** Event processing interface, processing event abstraction */public interface EventHandler {/*** Processing event * @ param subscribe object * @ param event to be processed event */void handleEvent (subscribe, object event );}
Code 7
By default, DefaultEventHandler, UIThreadEventHandler, and AsyncEventHandler are implemented as follows:
DefaultEventHandler: the thread in which the event is published, the thread where the event receiving function is executed; UIThreadEventHandler: executes the event receiving function in the UI thread; AsyncEventHandler: executes the event receiving function in the asynchronous thread.
The following uses a custom asynchronous event processor, AsyncEventHandler, to execute the event processing function in a thread pool through the EventHandler interface, so as to download images. As shown in code 8.
public class ThreadPoolHandler implements EventHandler { ExecutorService mExecutorService = Executors.newFixedThreadPool(3); EventHandler mHandler = new DefaultEventHandler(); @Override public void handleEvent(final Subscription subscription, final Object event) { mExecutorService.submit(new Runnable() { @Override public void run() { mHandler.handleEvent(subscription, event); } }); } }
Code 8
Run the following code to inject ThreadPoolEventHandler into AndroidEventBus:
// Custom asynchronous event processor, using the thread pool EventBus. getDefault (). setAsyncEventHandler (new ThreadPoolHandler ());
Then add the subscription method shown in code 9 to the subscription object:
@ Subcriber (tag = "download", mode = ThreadMode. ASYNC) private void downloadImage (final String imageUrl) {HttpURLConnection urlConnection = null; try {final URL url = new URL (imageUrl); urlConnection = (HttpURLConnection) url. openConnection (); final Bitmap bmp = BitmapFactory. decodeStream (urlConnection. getInputStream (); // deliver Bitmap to work like ImageView} catch (IOException e) {} finally {if (urlConn Ection! = Null) {urlConnection. disconnect ();}}}
Code 9
Finally, when you need to download an image, publish an event whose parameter is String type and tag is download through post to execute the downloadImage function, which will be executed in the thread pool, our simple ImageLoader is implemented in this way.
|
|
Figure 2 downloading images |
Figure 3 image download completed |
Of course, due to the high customization of AndroidEventBus, we can also use AndroidEventBus to implement a variety of functions. I will not demonstrate much about how it can be played, developers can make full use of their talents and imagination.