如果對於AndroidEventBus不瞭解的同學請移步 AndroidEventBus的設計與實現。AndroidEventBus庫的github地址在這裏。
新版特性
- 支持Sticky事件;
- 弱引用持有訂閱者,避免內存泄露。
什麼是Sticky事件?
關於Sticky事件有的同學可能不是很熟悉,Sticky的意思是粘性的。在Android開發中,Sticky事件只指事件消費者在事件發佈之後才註冊的也能接收到該事件的特殊類型。Android中就有這樣的實例,也就是Sticky Broadcast,即粘性廣播。正常情況下如果發送者發送了某個廣播,而接收者在這個廣播發送後才註冊自己的Receiver,這時接收者便無法接收到剛纔的廣播,爲此Android引入了StickyBroadcast,在廣播發送結束後會保存剛剛發送的廣播(Intent),這樣當接收者註冊完Receiver後就可以接收到剛纔已經發布的廣播。這就使得我們可以預先處理一些事件,讓有消費者時再把這些事件投遞給消費者。
AndroidEventBus也提供了這樣的功能,有所不同是AndroidEventBus會存儲所有的Sticky事件,如果某個事件在不需要再存儲則需要手動進行移除。用戶通過Sticky的形式發佈事件,而消費者也需要通過Sticky的形式進行註冊,當然這種註冊除了可以接收Sticky事件之外和常規的註冊功能是一樣的,其他類型的事件也會被正常處理。發佈、接收Sticky事件的步驟有如下幾步 :
1、發佈Sticky事件;
EventBus.getDefault().postSticky("hello");
2、 某個時刻訂閱者以Sticky的形式註冊
public class MyReceiver {
public MyReceiver() {
EventBus.getDefault().registerSticky(this);
}
@Subscriber
private void onStickyEvent(String info) {
System.out.println("接收到事件 : " + info);
}
}
當在某個時刻構造MyReceiver時就會將MyReceiver對象以Sticky的形式註冊到EventBus中,此時先前發佈的”hello”事件就會被MyReceiver對象接收到,因此就會執行onStickyEvent
函數,在該函數中實現具體的邏輯即可。當然,不要忘了在某個時刻將MyReceiver註銷,以弱引用的形式持有訂閱者的功能還沒有完成吶!整個過程就這樣結束了~
Sticky事件的運用場景
上文中我們簡單講述了Sticky事件的基本使用步驟,這裏我們以一個具體的示例來看看Sticky事件在開發中的使用場景。
在開發過程中,我們經常需要在Activity之間傳值,我們的做法就是將數據塞到Intent中,並且爲每個數據設置一個key。當我們傳遞的數據是一個實體類時,我們的這個類還需要實現序列化接口,比如Parcelable或者Serializable。例如我們需要將一個用戶對象傳遞到用戶個人信息展示頁面。我們的常規做法是這樣的:
User.java類 :
// 實體類實現序列化
public class User implements Parcelable {
String name ;
String phoneNum;
// 其他字段省略
public User(String aName) {
name = aName ;
}
public User(Parcel in) {
super(in);
name = in.readString();
phoneNum = in.readString();
}
// 代碼省略
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(phoneNum);
}
public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {
@Override
public User createFromParcel(Parcel source) {
return new User(source);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
}
然後我們要在某個Activity中將這個用戶數據傳遞給個人信息界面ProfileActivity。代碼如下 :
public class MainActivity extends Activity {
// 某個點擊事件
@Override
public void onClick(View v) {
User aUser = new User("Mr.Simple");
aUser.phoneNum = "123456";
// 其他數據
Intent intent = new Intent(this, ProfileActivity.class);
intent.putParcelable("user", aUser);
startActivity(intent);
}
}
在某個點擊事件的處理函數中我們通過Intent將數據傳遞給ProfileActivity。我們再看看ProfileActivity從Intent中取出數據的代碼。
public class ProfileActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
// 從Bundle中獲取數據
Bundle extraBundle = getIntent().getExtras();
if (extraBundle != null) {
User user = extraBundle.getParcelable("user");
}
}
}
OK,至此整個過程纔算結束了。
大哥,我只是需要傳個數據啊!何苦啊!
這種方式產生了很多的樣板代碼,也讓邏輯變得更復雜,容易出錯。我們再看看使用Sticky事件的實現方式。
User.java類 :
// 實體類實現序列化
public class User {
String name ;
String phoneNum;
// 其他字段省略
public User(String aName) {
name = aName ;
}
// 代碼省略
}
首先User類不需要實現序列化接口,避免了那些樣板代碼。然後在MainActivity中直接將User對象作爲Sticky事件發佈即可。
public class MainActivity extends Activity {
// 某個點擊事件
@Override
public void onClick(View v) {
User aUser = new User("Mr.Simple");
aUser.phoneNum = "123456";
// 其他數據
// 發佈Sticky事件
EventBus.getDefault().postSticky(aUser);
// 跳轉到ProfileActivity頁面
Intent intent = new Intent(this, ProfileActivity.class);
startActivity(intent);
}
}
最後我們看看ProfileActivity如何接收數據。
public class ProfileActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
// 以Sticky的形式註冊
EventBus.getDefault().registerSticky(this);
}
@Subscriber
private void receiveUser(User info){
// 這裏實現你的邏輯即可, info即爲傳遞過來的User對象
}
}
在ProfileActivity中我們將ProfileActivity自身作爲訂閱者註冊到總線當中,此時ProfileActivity就會接收到上面發佈的Sticky事件,這個事件對象就是User對象。此時就會觸發ProfileActivity 中的receiveUser函數,info參數就是Sticky事件的那個用戶信息對象,在receiveUser中實現自己的邏輯即可。
是的!我們並沒有在onDestory中對訂閱者進行註銷,也就是沒有調用EventBus的unregister()函數,這就是最新版的特性之一,也是目前唯一不需要手動註銷的事件總線庫。
問題是不是簡單了很多~ 還有什麼場景可以使用Sticky事件呢?Sticky事件是否應該消費完之後自動移除?這些問題大家可以自行思考或者給我留言([email protected]),謝謝。