EventBus 3.0接入問題
在開發過程中,為了避免頁面之間的數據層層傳遞,很容易就想到使用訂閱/發布的形式來傳遞數據,有一個出名開源庫就是做這類事情的
那么如何在自己的項目中集成這個庫呢?在上面給出的鏈接中,官方給出了集成的步驟,為了方便說明,直接貼過來:
EventBus in 3 steps
- Define events:
public static class MessageEvent { /* Additional fields if needed */ }
- Prepare subscribers: Declare and annotate your subscribing method, optionally specify a thread mode :
@Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) {/* Do something */};
- Register and unregister your subscriber. For example on Android, activities and fragments should usually register according to their life cycle:
@Overridepublic void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Overridepublic void onStop() { super.onStop(); EventBus.getDefault().unregister(this); }
Post events:
EventBus.getDefault().post(new MessageEvent());
看完這個步驟,那么開始著手寫一個樣例,樣例是這樣的:
有三個頁面,第一個頁面點擊一個按鈕進入到第二個頁面,第二個頁面點擊一個按鈕進入到第三個頁面,第三個頁面點擊一個按鈕發出消息,第一個頁面和第二個頁面接收消息并展示出來,如下圖
下面開始編寫代碼,也很簡單:
FirstActivity.java
package com.vip.veblonwang.eventbus;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
public class FirstActivity extends Activity {
private TextView tvMsg;
private Button btnGoNext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
tvMsg = (TextView) findViewById(R.id.tvMsg);
btnGoNext = (Button) findViewById(R.id.btnGoNext);
btnGoNext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(SendMsgEvent event) {
final String msg = event.getMsg();
tvMsg.setText(msg);
}
}
activity_first.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="頁面一" />
<Button
android:id="@+id/btnGoNext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="下一個頁面"/>
<TextView
android:id="@+id/tvMsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>
SecondActivity.java
package com.vip.veblonwang.eventbus;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
public class SecondActivity extends Activity {
private TextView tvMsg;
private Button btnGoNext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
tvMsg = (TextView) findViewById(R.id.tvMsg);
btnGoNext = (Button) findViewById(R.id.btnGoNext);
btnGoNext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this, ThirdActivity.class);
startActivity(intent);
}
});
}
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(SendMsgEvent event) {
String msg = event.getMsg();
tvMsg.setText(msg);
}
}
activity_second.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="頁面二" />
<Button
android:id="@+id/btnGoNext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="下一個頁面"/>
<TextView
android:id="@+id/tvMsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>
ThirdActivity.java
package com.vip.veblonwang.eventbus;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import org.greenrobot.eventbus.EventBus;
public class ThirdActivity extends Activity {
private Button btnSendMsg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
btnSendMsg = (Button) findViewById(R.id.btnSendMsg);
btnSendMsg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().post(new SendMsgEvent("三千弱水,不飲一瓢!"));
}
});
}
}
activity_third.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第三個頁面" />
<Button
android:id="@+id/btnSendMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="發消息"/>
</LinearLayout>
到目前為止,三個頁面都寫完了,可以發現,官方定義的步驟在上面的代碼中都已經體現出來了,除了第一步,自己定義一個Event類(Define events)
SendMsgEvent.java
package com.vip.veblonwang.eventbus;
public class SendMsgEvent {
private String msg;
public SendMsgEvent(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
}
按照要求都做完了,接下來可以滿心歡喜地運行demo來看結果 ~~
demo的主頁面是頁面一,點擊按鈕后進入到頁面二,在頁面二點擊按鈕進入到第三個頁面,在第三個頁面點擊發消息后,一切正常。
關鍵的時刻到了,如果點擊返回鍵,會回到頁面二,頁面一,按照預計,頁面二和頁面一會展示出頁面三發出的消息。
可是,當你點擊返回的時候,看到的并非這樣,消息發出去了,但頁面一和頁面二并沒有接收到消息。
為什么會這樣呢?
仔細分析一下代碼,找到了問題所在,當頁面一進入到頁面二時,頁面一變不可見,其生命周期會調用onStop()方法,而在onStop()方法里,我們注銷了對消息事件的監聽(調用了 EventBus.getDefault().unregister(this); ),頁面二進入到頁面三時,也是一樣。所以在頁面三里發消息,他們是接收不到的。
如何解決呢?
我們期望在頁面變成不可見時,不要注銷掉eventbus,把注銷代碼寫在生命周期的onStop()事件中。在頁面一和頁面二里刪除onStart()方法,加上下面代碼。
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
修改完成后,再次運行demo,結果還是出人意料 ~
頁面三發完消息點擊返回時,程序無異常卻重啟了,查找日志卻只看見 I/Process: Sending signal. PID: 16048 SIG: 9
what the fuck !~什么情況?繼續排查問題出在什么地方 ~
在接收消息的方法里加入Toast提示:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(SendMsgEvent event) {
final String msg = event.getMsg();
tvMsg.setText(msg);
Toast.makeText(this, event.getMsg(), Toast.LENGTH_SHORT).show();
}
再次運行demo,在頁面三點擊發消息時,頁面一和頁面二確實收到了消息(因為有Toast彈出),但是當從頁面三返回到頁面二時就重啟了應用。
好的,那么問題出在了頁面二由不可見到可見這一個過程當中。
這個過程中會執行onRestart()-->onStart()-->onResume(),而這三個方法中我們只重寫了一個onStart(),并且里面只有一句話,那就是注冊eventbus。難道說是 一個頁面不能在未注銷eventbus時再注冊一次eventbus ?
如果是這樣,那么eventbus的注冊事件就不能寫在onStart()里,而應該寫在onCreate()里。
為了驗證這個想法,我們把eventbus注冊代碼寫到onCreate()方法里,再次運行demo,一切順利~~~
寫了這么多,其實是想說,應該 把注冊寫在onCreate()里,注銷寫在onDestory()里 ,不要被官方文檔給騙了~
來自:http://www.jianshu.com/p/2d4e435a3413