什么是EventBus:
EventBus是android下的高效的發(fā)布/訂閱總線機制,它的作用是可以代替?zhèn)鹘y(tǒng)的Intent,Handler,Broadcast,或者接口函數在Fragment,Activity,Service,線程之間傳遞數據,執(zhí)行方法,它用來傳遞數據特別方便,并且代碼簡潔,實現了代碼之間的解耦.是一種發(fā)布訂閱者模式,或者稱為觀察者設計模式
來一張EventBus的github上的框架原理流程圖
怎么使用EventBus:
1.引入EventBus,這里有兩種方法,一種是下載EventBus庫源碼地址:https://github.com/greenrobot/EventBus, 庫地址:https://github.com/greenrobot/EventBus/releases, ,將EventBus的jar文件放入libs中,第二中方法是直接在build.gradle中添加依賴, compile 'org.greenrobot:eventbus:3.0.0',
2.定義事件,前面已經說了,EventBus是事件發(fā)布總線,用來傳遞消息的,那么我們需要定義要傳遞的消息.定義一個類,繼承默認的Object即可,用來區(qū)分事件和傳遞數據,
3.添加訂閱者,一個類用成為訂閱者類,就必須注冊, EventBus.getDefault().register(this);通過注冊成為訂閱者之后,框架會通過反射機制獲取所有的方法和參數.
那么訂閱者是怎么接收發(fā)布者發(fā)布的事件的,這里就要講一下不同版本的EventBus的訂閱者接收事件的方法不一樣了,EventBus2.4的時候訂閱者所在的類可以定義以下一個或多個方法用以接收事件:
public void onEvent(MsgEvent1 msg)// 與發(fā)布者在同一個線程
public void onEventMainThread(MsgEvent1 msg)// 執(zhí)行在主線程。
public void onEventBackgroundThread(MsgEvent1 msg)// 執(zhí)行在子線程古劲,如果發(fā)布者是子線程則直接執(zhí)行该默,如果發(fā)布者不是子線程把鉴,則創(chuàng)建一個再執(zhí)行
public void onEventAsync(MsgEvent1 msg)// 執(zhí)行在在一個新的子線程
而在EventBus3.0之后就取消了約定好的方法定義,并提供了注解的方式進行監(jiān)聽.
@Subscribe(threadMode = ThreadMode.MAIN)
public void getEventBus(MyEvent event){
}
threadMode就是舊版本接收信息運行的方法。
4.發(fā)布者發(fā)布事件,所有類都可以成為發(fā)布者,訂閱者也可以作為發(fā)布者給自己發(fā)布消息, EventBus.getDefault().post(new MsgEvent1("主線程發(fā)的消息1"));一旦執(zhí)行了此方法, 所有訂閱者都會執(zhí)行第二步定義的方法阵具。
5.取消訂閱,一般訂閱者銷毀的時候在銷毀的生命周期方法中可以取消訂閱,不再接收消息, EventBus.getDefault().unregister(this)
需要注意的是發(fā)布者可以發(fā)布任何事件, 訂閱者接受消息時,只要定義的是第二步四個方法任意一個定铜,并且參數和發(fā)布者發(fā)布的一致阳液,即可被執(zhí)行。發(fā)布者也可以通過第二步接收消息揣炕,訂閱者也可以作為發(fā)布者發(fā)消息給自己趁舀。
下面通過一個Demo更好的認識EventBus:
引入EventBus,這里我用的是gradle的方式:
compile 'org.greenrobot:eventbus:3.0.0'
主界面:
/**因為主界面中要實現左邊一個fragment,右邊一個fragment,所以繼承FragmentActivity*/
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
主界面的xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="?android:attr/dividerHorizontal"
android:orientation="horizontal"
android:showDividers="middle"
android:baselineAligned="false"
tools:context=".MainActivity" >
<fragment
android:id="@+id/left_fragment"
android:name="com.xinguangnet.eventdemo.LeftFragment"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1" />
<fragment
android:id="@+id/right_fragment"
android:name="com.xinguangnet.eventdemo.RightFragment"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="3" />
</LinearLayout>
定義事件:
public class MsgEvent1 {
private String msg;
public MsgEvent1(String msg) {
super();
this.msg = msg;
}
public String getMsg() {
return msg;
}
}
右邊的fragment,作為接收者:
創(chuàng)建的時候注冊,銷毀的時候取消注冊:
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//界面創(chuàng)建時就訂閱事件接收消息
EventBus.getDefault().register(this);
}
@Override
public void onDestroy() {
super.onDestroy();
//界面銷毀時取消訂閱
EventBus.getDefault().unregister(this);
}
接收事件的方法:
/**
* 與發(fā)布者在同一個線程
* @param msg 事件1
*/
@Subscribe
public void onEvent(MsgEvent1 msg){
String content = msg.getMsg()
+ "\n ThreadName: " + Thread.currentThread().getName()
+ "\n ThreadId: " + Thread.currentThread().getId();
System.out.println("onEvent(MsgEvent1 msg)收到" + content);
}
/**
* 執(zhí)行在主線程。
* 非常實用祝沸,可以在這里將子線程加載到的數據直接設置到界面中矮烹。
* @param msg 事件1
*/
@Subscribe
public void onEventMainThread(MsgEvent1 msg){
String content = msg.getMsg()
+ "\n ThreadName: " + Thread.currentThread().getName()
+ "\n ThreadId: " + Thread.currentThread().getId();
System.out.println("onEventMainThread(MsgEvent1 msg)收到" + content);
tv.setText(content);
}
/**
* 執(zhí)行在子線程越庇,如果發(fā)布者是子線程則直接執(zhí)行,如果發(fā)布者不是子線程奉狈,則創(chuàng)建一個再執(zhí)行
* 此處可能會有線程阻塞問題卤唉。
* @param msg 事件1
*/
@Subscribe
public void onEventBackgroundThread(MsgEvent1 msg){
String content = msg.getMsg()
+ "\n ThreadName: " + Thread.currentThread().getName()
+ "\n ThreadId: " + Thread.currentThread().getId();
System.out.println("onEventBackgroundThread(MsgEvent1 msg)收到" + content);
}
/**
* 執(zhí)行在在一個新的子線程
* 適用于多個線程任務處理, 內部有線程池管理仁期。
* @param msg 事件1
*/
@Subscribe
public void onEventAsync(MsgEvent1 msg){
String content = msg.getMsg()
+ "\n ThreadName: " + Thread.currentThread().getName()
+ "\n ThreadId: " + Thread.currentThread().getId();
System.out.println("onEventAsync(MsgEvent1 msg)收到" + content);
}
/**
* 與發(fā)布者在同一個線程
* @param msg 事件2
*/
@Subscribe
public void onEvent(MsgEvent2 msg){
String content = msg.getMsg()
+ "\n ThreadName: " + Thread.currentThread().getName()
+ "\n ThreadId: " + Thread.currentThread().getId();
System.out.println("onEvent(MsgEvent2 msg)收到" + content);
tv.setText(content);
}
左邊的fragment用來發(fā)布消息:
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
String[] strs = new String[]{"主線程消息1", "子線程消息1", "主線程消息2"};
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, strs));
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
switch (position) {
case 0:
// 主線程
System.out.println(
"----------------------主線程發(fā)的消息1"
+ " threadName: " + Thread.currentThread().getName()
+ " threadId: " + Thread.currentThread().getId());
EventBus.getDefault().post(new MsgEvent1("主線程發(fā)的消息1"));
break;
case 1:
// 子線程
new Thread() {
public void run() {
System.out.println(
"----------------------子線程發(fā)的消息1"
+ " threadName: " + Thread.currentThread().getName()
+ " threadId: " + Thread.currentThread().getId());
EventBus.getDefault().post(new MsgEvent1("子線程發(fā)的消息1"));
}
;
}.start();
break;
case 2:
// 主線程
System.out.println(
"----------------------主線程發(fā)的消息2"
+ " threadName: " + Thread.currentThread().getName()
+ " threadId: " + Thread.currentThread().getId());
EventBus.getDefault().post(new MsgEvent2("主線程發(fā)的消息2"));
break;
}
}
這個Demo寫完之后運行起來有一個出現了bug,我開始百思不得其解,后來反復看了錯誤日志,終于知道了原因
我引入的EventBus3.0但是一開始在訂閱者的接收方法里面沒有加注解,所以報了以上的錯誤