EventBus使用
在介紹EventBus之前先捋順以下Android自帶的應用內通信方式有哪些?
Android 應用內常用通信方式
1.使用handler進行線程間通信
handler是和Thread綁定的,主線程中創建Hander直接通過new Handler() 來創建即可。自定義線程中則還需要調用Looper.prepare Looper.loop來讓Handler起作用,這裏就不詳細講解原理及使用了,感興趣的自己去探索一下。
Handler主要有兩個作用,一個是線程間傳遞消息, 另一個則是post Runnable對象,讓Runnable對象在Handler對應的那個線程裏運行。
下面用最小代碼簡單介紹展示一下Handler在線程間傳遞消息的方式。
示例代碼:
新建一個線程,延遲1s後通過主線程的Handler發送消息。
主線程的Handler收到消息後,打印log
public class MainActivity extends Activity{
private Handler mHandler;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=(Button) findViewById(R.id.button1);
mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what==0xff){
Log.e("what", "I got the Message");
}
}
};
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.sendEmptyMessage(0xff);
}
}).start();
}
});
}
}
2.使用Interface定義回調,可以用在任意兩個對象之間。比如Activity和Fragment通信
Android官方的Guides也是這麼建議的
參考(http://developer.android.com/guide/components/fragments.html和http://developer.android.com/training/basics/fragments/communicating.html)
public static class FragmentA extends ListFragment {
...
// Container Activity must implement this interface
public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
//在Fragment的onAttach方法中,綁定mListener(也就是需要實現了該接口的Activity)
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
//當Fragment中的Item點擊後,回調OnArticleSelectedListener的方法。Activity中實現的方法中即可做相應處理
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Append the clicked item's row ID with the content provider Uri
Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
// Send the event and Uri to the host activity
mListener.onArticleSelected(noteUri);
}
}
在Activity中需要實現FragmentA中的OnArticleSelectedListener接口
public class MainActivity extends Activity implements FragmentA.OnArticleSelectedListener{
@Override
public void onArticleSelected(Uri articleUri) {
//Do something to response the Item selection
}
}
使用Intent進行組件間的通信
通過Intent來比如啓動Service,啓動Activity,
通過Intent來發送Broadcast,然後註冊一個BroadcastReceiver來接收並處理Intent. 這個部分比較基礎,就不再贅述了。
EventBus進行應用內通信
如果想深入瞭解EventBus的實現原理,可以參考 EventBus 源碼解析
簡介
EventBus是Android端的一個訂閱/發佈的消息總線,用在應用程序內,組件之間,線程之間的通信,並且由於事件可以是任意類型的對象,所以使用起來更加的方便快捷。
角色:
Event:就是事件啦
Subscriber:訂閱者,接收特定事件的對象,主要通過onEventXXX()回調接口接收
Publisher:發佈者,post事件,通知訂閱者
其他的先不多介紹了,後面慢慢展開。
使用過程
使用EventBus只有簡單的4步
- 1 定義一個Event事件
- 2 註冊一個訂閱者
- 3 發佈一個事件
- 4 接受這個事件
用代碼實現這4步就是:
- 1 public class MyEvent()–可以是任意Object
- 2 EventBus.getDefault().register(this)—比如這時一個Activity,那就等於把Activity註冊爲一個訂閱者
- 3 EventBus.getDefault().post(event)—隨便哪個組件或者線程中發送出一個MyEvent的對象
- 4 public void onEvent(MyEvent event)–第2步中的Activity中的onEvent方法接收到該事件並處理。注意一定Event類型要對應。如果寫成了onEvent(Object event),那就是post什麼類型的Event都能接受了。
看起來的確很方便。下面給出一個Activity中的完整代碼。也是比較簡單,但是能夠很清晰的看出EventBus是如何使用的。
示例代碼
public class MainActivity extends Activity{
private TextView textView;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=(Button) findViewById(R.id.button1);
textView= (TextView) findViewById(R.id.textView1);
//1.註冊訂閱者
EventBus.getDefault().register(this);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//post事件
EventBus.getDefault().post(new MyEvent());
}
});
}
//接收事件的回調
public void onEvent(MyEvent event){
Log.e("What", "[onEvent]My Thread is "+Thread.currentThread().getName());
}
自定義的事件就是一個空的類,當然也可以加入不同的屬性,方法。用來傳遞信息。
public class MyEvent {
}
點擊按鈕後可以看到TextView的內容已更改。
Log
03-29 18:56:22.738: E/What(17402): [onEvent]My Thread is main
onEventXXXX
onEvent函數一共有四種,前面的例子只用到一個onEvent。
函數名 | 含義 | ThreadMode |
---|---|---|
onEvent | 事件處理在事件發送的那個線程執行 | PostThread |
onEventMainThread | 事件在主線程-UI線程執行 | MainThread |
onEventBackgroundThread | 事件在一個後臺線程執行(就一個後臺線程) | BackgroundThread |
onEventAsync | 事件會單獨啓動一個線程執行(每個事件都會啓動一個線程) | Async |
其中前三個事件處理方式,都應該儘快完成。
onEventMainThread使用演示
onEventMainThread就是會放到主線程去執行的事件處理,一般在其中進行比如UI的更新的操作,比如TextView的更改。下面通過代碼展示一下。一個自定義的線程發送該事件,Activity通過onEventMainThread接收到該事件,並更新UI.這個時候就不能使用onEvent了,因爲根據上表所示,onEvent會放在發送事件的那個線程中去執行,其實不能進行UI更新操作的。
示例代碼
public class MainActivity extends Activity{
private TextView textView;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=(Button) findViewById(R.id.button1);
textView= (TextView) findViewById(R.id.textView1);
//1.註冊訂閱者
EventBus.getDefault().register(this);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new MyEvent());
}
}).start();
}
});
}
public void onEvent(MyEvent event){
Log.e("What", "[onEvent]My Thread is "+Thread.currentThread().getName());
}
public void onEventMainThread(MyEvent event){
Log.e("What", "[onEventMainThreadMy] Thread is "+Thread.currentThread().getName());
textView.setText("onEventMainThread called");
}
}
點擊按鈕後可以看到TextView的內容已更改。
Log
03-29 18:54:10.728: E/What(16993): [onEvent]My Thread is Thread-67572
03-29 18:54:10.778: E/What(16993): [onEventMainThreadMy] Thread is main
Sticky Event
Sticky Event是指我註冊一個sticky的訂閱,這樣註冊之前發送的sticky事件的最近的一個會保存在內存中,錯過這個事件的發送的情況下,也可以通過getStickyEvent收到。
- postSticky(event) :發送sticky的event
- registerSticky(subscriber) :註冊接收sticky事件的訂閱者
- getStickyEvent(Class
示例代碼
public class MyEvent {
public String what;
public MyEvent(String what) {
super();
this.what = what;
}
}
package com.example.eventbusdemo;
import de.greenrobot.event.EventBus;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private TextView textView;
private Button sendEvent;
private Button quaryEvent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sendEvent = (Button) findViewById(R.id.button1);
quaryEvent = (Button) findViewById(R.id.button2);
textView = (TextView) findViewById(R.id.textView1);
// 1.註冊訂閱者
EventBus.getDefault().registerSticky(this);
sendEvent.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 點擊按鍵發送5個Sticky event
for (int i = 0; i < 5; i++) {
EventBus.getDefault().postSticky(
new MyEvent(String.valueOf(i)));
}
}
});
quaryEvent.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
MyEvent lastEvent = EventBus.getDefault().getStickyEvent(
MyEvent.class);
Log.e("What", "[quaryEvent] last Event is" + lastEvent.what);
}
});
}
public void onEvent(MyEvent event) {
Log.e("What", "[onEvent] this Event is" + event.what);
}
}
結果
點擊sendEvent按鈕:
Log
03-29 19:09:40.698: E/What(20520): [onEvent] this Event is0
03-29 19:09:40.698: E/What(20520): [onEvent] this Event is1
03-29 19:09:40.698: E/What(20520): [onEvent] this Event is2
03-29 19:09:40.698: E/What(20520): [onEvent] this Event is3
03-29 19:09:40.698: E/What(20520): [onEvent] this Event is4
點擊quaryEvent按鈕:
Log
03-29 19:12:31.578: E/What(20520): [quaryEvent] last Event is4
技巧
Event類一般都比較小,所以可以把它們都打包在一個Events類中。比如:
public class Events{
public static class AbcEvent{
}
public static class XyzEvent{
}
}