什么是EventBus
EventBus是Android下高效的發(fā)布/訂閱事件總線機制。作用是可以代替?zhèn)鹘y(tǒng)的Intent,Handler,Broadcast或接口函數(shù)在Fragment,Activity,Service,線程之間傳遞數(shù)據(jù),執(zhí)行方法,也可以通過調(diào)用普通類開啟發(fā)送消息。特點是代碼簡潔,是一種發(fā)布訂閱設(shè)計模式(Publish/Subsribe),或稱作觀察者設(shè)計模式。
如何使用EventBus

EventBus.png
- Publisher是發(fā)布者, 通過post()方法將消息事件Event發(fā)布到事件總線
- EventBus是事件總線, 遍歷所有已經(jīng)注冊事件的訂閱者們,找到里邊的onEvent等4個方法,分發(fā)Event
- Subscriber是訂閱者, 收到事件總線發(fā)下來的消息。即onEvent方法被執(zhí)行。注意參數(shù)類型必須和發(fā)布者發(fā)布的參數(shù)一致。
MainActivity.java
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
activity_main.xml
<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="com.itheima.eventbusdemo.MainActivity" >
<fragment
android:id="@+id/left_fragment"
android:name="com.itheima.eventbusdemo.LeftFragment"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1" />
<fragment
android:id="@+id/right_fragment"
android:name="com.itheima.eventbusdemo.RightFragment"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="3" />
</LinearLayout>
fragment_left.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/bt"
android:textSize="14sp"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按鈕" />
</RelativeLayout>
fragment_right.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/bt"
android:textSize="14sp"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按鈕" />
</RelativeLayout>
LeftFragment.java
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import de.greenrobot.event.EventBus;
public class LeftFragment extends ListFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
String[] strs = new String[]{"主線程消息1", "子線程消息1", "主線程消息2","通過普通類發(fā)送消息"};
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;
case 3:
// 子線程2
new Thread(){
public void run() {
System.out.println("----------------------子線程發(fā)的類EventBus1消息1"
+ " threadName: "+ Thread.currentThread().getName()
+ " threadId: " + Thread.currentThread().getId());
new EventBus1();//調(diào)用類EventBus1傳送消息
}
}.start();
}
}
}
RightFragment.java
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import de.greenrobot.event.EventBus;
public class RightFragment extends Fragment {
private TextView tv;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 界面創(chuàng)建時,訂閱事件, 接受消息
EventBus.getDefault().register(this);
}
@Override
public void onDestroy() {
super.onDestroy();
// 界面銷毀時,取消訂閱
EventBus.getDefault().unregister(this);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_right, null);
tv = (TextView) view.findViewById(R.id.tv);
return view;
}
/**
* 與發(fā)布者在同一個線程
* @param msg 事件1
*/
public void onEvent(MsgEvent1 msg){
String content = msg.getMsg()
+ "\n ThreadName: " + Thread.currentThread().getName()
+ "\n ThreadId: " + Thread.currentThread().getId()+"\n onEvent";
System.out.println("onEvent(MsgEvent1 msg)收到" + content);
}
/**
* 執(zhí)行在主線程。
* 非常實用,可以在這里將子線程加載到的數(shù)據(jù)直接設(shè)置到界面中。
* @param msg 事件1
*/
public void onEventMainThread(MsgEvent1 msg){
String content = msg.getMsg()
+ "\n ThreadName: " + Thread.currentThread().getName()
+ "\n ThreadId: " + Thread.currentThread().getId()+"\n onEventMainThread";
System.out.println("onEventMainThread(MsgEvent1 msg)收到" + content);
tv.setText(content);
}
/**
* 執(zhí)行在子線程,如果發(fā)布者是子線程則直接執(zhí)行,如果發(fā)布者不是子線程,則創(chuàng)建一個再執(zhí)行
* 此處可能會有線程阻塞問題。
* @param msg 事件1
*/
public void onEventBackgroundThread(MsgEvent1 msg){
String content = msg.getMsg()
+ "\n ThreadName: " + Thread.currentThread().getName()
+ "\n ThreadId: " + Thread.currentThread().getId()+"\n onEventBackgroundThread";
System.out.println("onEventBackgroundThread(MsgEvent1 msg)收到" + content);
}
/**
* 執(zhí)行在在一個新的子線程
* 適用于多個線程任務(wù)處理, 內(nèi)部有線程池管理。
* @param msg 事件1
*/
public void onEventAsync(MsgEvent1 msg){
String content = msg.getMsg()
+ "\n ThreadName: " + Thread.currentThread().getName()
+ "\n ThreadId: " + Thread.currentThread().getId()+"\n onEventAsync";
System.out.println("onEventAsync(MsgEvent1 msg)收到" + content);
}
/**
* 與發(fā)布者在同一個線程
* @param msg 事件2
*/
public void onEvent(MsgEvent2 msg){
String content = msg.getMsg()
+ "\n ThreadName: " + Thread.currentThread().getName()
+ "\n ThreadId: " + Thread.currentThread().getId()+"\n msg2";
System.out.println("onEvent(MsgEvent2 msg)收到" + content);
tv.setText(content);
}
}
MsgEvent1.java
public class MsgEvent1 {
private String msg;
public MsgEvent1(String msg) {
super();
this.msg = msg;
}
public String getMsg() {
return msg;
}
}
MsgEvent2.java
public class MsgEvent2 {
private String msg;
public MsgEvent2(String msg) {
super();
this.msg = msg;
}
public String getMsg() {
return msg;
}
}
EventBus1.java
import de.greenrobot.event.EventBus;
public class EventBus1 {
public EventBus1() {
// TODO Auto-generated constructor stub
EventBus.getDefault().post(new MsgEvent1("類EventBus1發(fā)的消息1"));
}
}
效果圖:

效果圖.gif
源碼地址:https://git.oschina.net/Fly321/EventBus.git
EventBus的ThreadMode
EventBus包含4個ThreadMode:PostThread,MainThread,BackgroundThread,Async
MainThread我們已經(jīng)不陌生了;我們已經(jīng)使用過。
具體的用法,極其簡單,方法名為:onEventPostThread, onEventMainThread,onEventBackgroundThread,onEventAsync即可
具體什么區(qū)別呢?
- onEventMainThread代表這個方法會在UI線程執(zhí)行
- onEventPostThread代表這個方法會在當(dāng)前發(fā)布事件的線程執(zhí)行
- BackgroundThread這個方法,如果在非UI線程發(fā)布的事件,則直接執(zhí)行,和發(fā)布在同一個線程中。如果在UI線程發(fā)布的事件,則加入后臺任務(wù)隊列,使用線程池一個接一個調(diào)用。
Async 加入后臺任務(wù)隊列,使用線程池調(diào)用,注意沒有BackgroundThread中的一個接一個。