Use of EventBus in Android (2): cache events, androideventbus
In the previous article, I mentioned that I chose EventBus (Android platform) provided by Green Robot, and this is not just my choice. In the last check, I found that the number of people who selected it was already twice that of Otto (the version provided by Jake Wharton and other great gods on Square. The GR version obviously has more performance improvements than Otto, but the most exciting thing is that it has added many new features. Today I am going to talk about one of them: using the sticky event for event caching.
What is sticky?
Sticky events are events cached in EventBus. EventBus stores the last sent event-sticky for each class type. Subsequent sticky events of the same type will automatically replace the previously cached events. When a listener registers with EventBus, it may request these cache events. At this time, all cached events will be automatically sent to the listener immediately, just as these events have been re-sent once. This means that a listener can receive events that have been sent to EventBus before it is registered (or even before the listener's instance is created ). This powerful feature will help us solve some inherent problems, such as the complicated issue of transferring data across Activity and Fragment lifecycles on Android, asynchronous calls, and so on.
Use sticky
To use the sticky event, you need:
- 1. The sender must cache the event by calling bus. postSticky (event.
- 2. the listener must call bus. registerSticky (this) to obtain the cached events.
When bus. registerSticky (this) is called, The Listener immediately receives all cached events that have been defined in the onEvent handler. In addition, the listener can also obtain these cache events through bus. getStickyEvent (SomeEvent. class) as needed.
(Note: Calling postSticky will send the event to all the listeners of the current activity like a normal post call, rather than those registered through registerSticky. RegisterSticky only enables cache events to be resent during registration .)
The time when the sticky event exists in the cache is not determined. So if you want to eliminate cached events at a certain time so that they are no longer sent, you can use bus. removeStickyEvent (event) or bus. removeStickyEvent (SomeEvent. class), and bus. removeAllStickyEvents.
Annoying Bundles
As I mentioned in the previous article, I do not like Bundle in Android and try to avoid using them. I do not like to be restricted by objects such as Serializable or Parcelable. In particular, they still lack type security checks. I mean, it must be Java, not Python or Javascript. I want my IDE to discover and tell me such errors. For example, a component sends an object type to another component that is not what it expects.
Do not misunderstand that Intent is useful for inter-process communication. In this case, it is reasonable to serialize the data carried into a common format. But if the user only wants to keep the program in its original state after rotating the screen, in the name of science, is it necessary to use this method? Yes, I am talking about the standard mode for processing configuration changes provided by Android-saving and restoring State data in onSaveInstanceState (Bundle bundle) and onRestoreInstanceState (Bundle bundle Bundle. Not to mention the absurd and complex Fragment lifecycle issues, this is just a way to maintain the running status, which is one of my favorite Android development features.
Stinky Bundles Sticky Events
In addition to saving the program running status to Bundle, another method is to save them to some objects that still exist when the configuration changes. The EventBus of GR has built-in caching mechanism for us to use.
Consider the following standard scenario for responding to the "Master/Detail process:
- A List component (usually Fragment) displays a summary List.
- Another component (another Fragment) displays the details of each item.
- Click a list item to display the corresponding details.
- In portrait mode, the list and details are divided into two pages, each occupying one screen, and only one page can be seen at a time.
- In Landscape mode, the list is on the left side of the screen, and the details are on the right side. When the list items on the left side are selected, the details on the right side are also changed.
- The main Activity contains a layout for switching between different modes.
In this example, it is challenging to maintain the status of the selected program when you switch back and forth between landscape and landscape screens. The importance of this status is not only that the details page needs to know which details to display, but also that the list needs to show which items are selected. In addition, you also need to know whether a project is selected on the home page to determine which page, list, or details to load in portrait mode.
As you can see, all three components need the same status information (selected items ). In the traditional method, each of the three components needs to save the status in the Bundle in their onSaveInstanceState method, and then retrieve the data from their onResumeInstanceState method. Unhappy!
However, using the sticky event makes things much easier. To better illustrate the problem, I created an Android sample project: All the sample code below the https://github.com/wongcain/EventBus-Config-Demo/ is included in this project.
First, create an event class (ItemSelectedEvent. java) to pass the location information of the selected item:
Java
| 123456 |
Public class ItemSelectedEvent {public final int position; public ItemSelectedEvent (int position) {this. position = position ;}} |
Then, send a sticky event in the listItemClick method of the List component (ItemListFragment. java:
Java
| 12345 |
@ Overridepublic void onListItemClick (ListView listView, View itemView, int position, long id) {super. onListItemClick (listView, itemView, position, id); bus. postSticky (new ItemSelectedEvent (position ));} |
Next, the Detail component (ItemDetailFragment. java) registers to receive sticky events and defines a processing method for ItemSelectedEvent. When an event is received, query and display the details of the selected item:
Java
| 1234567891011121314151617181920 |
@ Overridepublic void onResume () {super. onResume (); bus. registerSticky (this) ;}@ Overridepublic void onPause () {bus. unregister (this); super. onPause ();}... public void onEvent (ItemSelectedEvent event) {Item item = MockDataSource. ITEMS. get (event. position); titleView. setText (item. title); dateView. setText (item. getDateStr (); bodyView. setText (item. body );} |
Finally, all content is aggregated in the Main component (MainActivity. java. The Activity registers to listen to the sticky event and creates the same ItemSelectedEvent processing method as the Detail component. When an event is received, layout determines which appropriate container the Detail fragment is loaded.
Java
| 12345678910111213141516171819202122232425 |
@ Overrideprotected void onResume () {super. onResume (); bus. registerSticky (this); bus. postSticky (new LayoutEvent (isTwoPane () ;}@ Overrideprotected void onPause () {bus. unregister (this); super. onPause ();} public void onEvent (ItemSelectedEvent event) {if (isTwoPane () {getFragmentManager (). beginTransaction (). replace (detailContainer. getId (), new ItemDetailFragment ()). commit ();} else {getFragmentManager (). beginTransaction (). replace (listContainer. getId (), new ItemDetailFragment ()). addToBackStack (ItemDetailFragment. class. getName ()). commit ();}} |
Note that this activity not only listens to the sticky event, but also sends another sticky event to pass the current screen mode. This event will be subsequently received by List fragment (ItemListFragment. java) and set the List according to the conditions:
Java
| 12345678 |
Public void onEvent (LayoutEvent event) {if (event. isTwoPane) {getListView (). setChoiceMode (ListView. CHOICE_MODE_SINGLE); updateSelectedItem (activePosition);} else {getListView (). setChoiceMode (ListView. CHOICE_MODE_NONE );}} |
In addition, we can see that no component is going to implement the onSaveInstanceState (Bundle bundle) and onRestoreInstanceState (Bundle bundle) methods. Instead, they simply rely on the cache events automatically sent when registerSticky (this. Therefore, when you select a project and view the details, the configuration will automatically change as follows:
I hope this article will help you. As mentioned earlier, all the sample code can be accessed here: https://github.com/wongcain/EventBus-Config-Demo/
The next article will be the last article about the EventBus series. I will talk about the multi-thread and process-crossing content in EventBus.
Q: an online interaction platform APP for programmers and knowledge sharing
Q: Based on the sharing economy theory, one-click call mode is introduced to solve the technical problems encountered by programmers in their work.
Technical difficulties to improve work efficiency.
Product Form: mobile client
Http://www.wenaaa.com
Appstore and all major application markets can be downloaded