什麼是EventBus
先不去看官方的理解,我個人理解爲就是在任何你想和UI線程傳遞數據時候他都能給你進行數據傳遞,UI線程和傳輸數據的子線程是高度解耦合的,可以說是相當流氓,想怎麼傳數據就怎麼傳數據。
用法
用法比較簡單,首先在build.gradle裏添加
compile 'org.greenrobot:eventbus:3.0.0'
這裏爲了方便使用,同時添加了butterKnife的依賴,butterKnife的使用請自行百度
- 先聲明事件消息的實體類,並寫一個get方法
public class MyEvent {
private String msg ;
public MyEvent(String msg) {
this.msg= msg;
}
public String getMsg(){
return msg;
}
}
- 接下來我們創建兩個Activity,一個作爲接收方的MainActivity,另一個作爲發送方的SecondActivity
MainActivity
public class MainActivity extends AppCompatActivity {
@BindView(R.id.tv_1)
TextView tv_1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
EventBus.getDefault().register(this); //在要接收消息的地方註冊EventBus
}
@OnClick(R.id.btn_1)
public void onTest(View view){
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent); //跳轉到SecondActivity
}
//收到SecondActivity發送的消息
@Subscribe
public void onMessageEvent(MyEvent event){
String msg = event.getMsg();
tv_1.setText(msg); //將收到的消息輸入TextView
Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onDestroy(){
super.onDestroy();
EventBus.getDefault().unregister(this);//註銷EventBus
}
SecondActivity
public class SecondActivity extends AppCompatActivity {
@BindView(R.id.et_2)
EditText et_2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
ButterKnife.bind(this);
}
@OnClick(R.id.btn_2)
public void onTest2(View view){
String str = et_2.getText().toString(); //獲取EditText內容
EventBus.getDefault().post(new MyEvent(str)); //發送消息給MainActivity
super.onBackPressed(); //調用返回鍵回到MainActivity
}
}
兩個佈局文件
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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.eventbusdemo.MainActivity">
<TextView
android:id="@+id/tv_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
/>
<Button
android:id="@+id/btn_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="跳轉到第二個界面"/>
</LinearLayout>
activity_second.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.eventbusdemo.SecondActivity">
<EditText
android:id="@+id/et_2"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btn_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="向第一個頁面發送消息,並顯示在TextView上"/>
</LinearLayout>
運行結果如下:
這樣就完成了一個簡單的使用EventBus來傳遞消息的Demo
EventBus的線程模式
EventBus有四種線程模式:
- ThreadMode: POSTING
這時候訂閱者執行的線程與事件的發佈者所在的線程爲同一個線程。也就是說事件由哪個線程發佈的,訂閱者就在哪個線程中執行。這個也是EventBus默認的線程模式,也就是說在上面的例子中用的就是這種ThreadMode。由於沒有線程的切換,也就意味消耗的資源也是最小的。如果一個任務不需要多線程的,也是推薦使用這種ThreadMode的。在EventBus以前的版本中對應onEvent方法。例如:
@Subscribe
public void onMessageEvent(MyEvent event){
........
}
或者
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessageEvent(MyEvent event){
.........
}
- ThreadMode: MAIN
從它的名字就很容易可以看出,他是在Android的主線程中運行的。如果提交的線程也是主線程,那麼他就和ThreadMode.POSTING一樣了。當然在這裏由於是在主線程中運行的,所以在這裏就不能執行一些耗時的任務。在EventBus以前的版本中對應onEventMainThread方法。例如:
//在Android主線程中執行
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MyEvent event){
.........
}
- ThreadMode: BACKGROUND
這種模式下,我們的訂閱者將會在後臺線程中執行。如果發佈者是在主線程中進行的事件發佈,那麼訂閱者將會重新開啓一個子線程運行,若是發佈者在不是在主線程中進行的事件發佈,那麼這時候訂閱者就在發佈者所在的線程中執行任務。在EventBus以前的版本中對應onEventBackground方法。例如:
//在後臺線程中執行
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessageEvent(MyEvent event){
.........
}
- ThreadMode: ASYNC
在這種模式下,訂閱者將會獨立運行在一個線程中。不管發佈者是在主線程還是在子線程中進行事件的發佈,訂閱者都是在重新開啓一個線程來執行任務。在EventBus以前的版本中對應onEventAsync方法。例如:
// 在獨立的線程中執行
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessageEvent(MyEvent event){
.........
}
具體例子不貼上來,根據實際情況調用就好
消息接收的優先級與取消事件
在EventBus中是可以定義接收消息的優先級的,就是指定誰先接收,誰後接收
用法如下:
//這裏使用默認的接收線程方式,不指定線程,根據發送方來確定
@Subscribe(priority = 1)
public void onMessageEvent1(MyEvent event){
Log.d("1", "1收到了消息");
}
那麼我們就可以寫出這樣的例子:
public class MainActivity extends AppCompatActivity {
@BindView(R.id.tv_1)
TextView tv_1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
EventBus.getDefault().register(this);
}
@OnClick(R.id.btn_1)
public void onTest(View view){
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);
}
@Subscribe(priority = 1)
public void onMessageEvent1(MyEvent event){
Log.d("1", "1收到了消息");
}
@Subscribe(priority = 2)
public void onMessageEvent2(MyEvent event){
Log.d("2", "2收到了消息");
}
@Subscribe(priority = 3)
public void onMessageEvent3(MyEvent event){
Log.d("3", "3收到了消息");
EventBus.getDefault().cancelEventDelivery(event); //取消事件
}
@Subscribe(priority = 4)
public void onMessageEvent4(MyEvent event){
Log.d("4", "4收到了消息");
}
@Subscribe(priority = 5)
public void onMessageEvent5(MyEvent event){
Log.d("5", "5收到了消息");
}
@Override
protected void onDestroy(){
super.onDestroy();
EventBus.getDefault().unregister(this);//註銷EventBus
}
}
從上面的代碼可以看出,我們定義了一系列的接收事件,並給它們定義優先級,並在優先級爲3的接收事件中取消消息發送事件,那麼執行的結果如下:
可以看出 優先級爲 2 和 1 的事件確實沒有接收到消息。
本文講解就到這裏,之後會陸續補充內容