<Android>greenrobot-EventBus,guava-Event Bus的异步实现

刚开始是从otto入手,但是otto不支持异步执行,所以后来才开始研究了Event Bus。关于Event Bus,先前搜索的时候,看到网上的实例,很碎,而且很多都是一样的内容,代码看下来基本上是分2套写法,这就带来了疑问,后来再仔细浏览原先的帖子发现了Event Bus有2套源码,一个是greenrobot的Event Bus,一个是google的guava Event Bus。今天谈论的并不是2套Event Bus的原理以及不同之处,这些内容基本在网上都有参考,暂时不在这里累赘介绍了,等有时间深入研究的时候可以再写一遍详细的Event Bus的介绍。这次主要的是介绍2套Event Bus的异步实现,网上中文页面搜索基本很少有Event Bus异步的介绍,有的话也是很简单的代码实例,而且尝试过后都是失败的,最后都是在外文网站上搜索到了关键的代码,好了不废话,直接上代码。

首先介绍的是greenrobot Event Bus


package com.benny.test;


import java.util.ArrayList;
import java.util.List;


import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
import de.greenrobot.event.EventBus;


public class MyEventByusTestActivity extends Activity implements OnClickListener {

private EventBus eventBus = EventBus.getDefault();
private LinearLayout viewGroup;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        viewGroup = (LinearLayout)findViewById(R.id.main_layout);

// 按钮设置响应接口
        findViewById(R.id.postthread).setOnClickListener(this);
        findViewById(R.id.mainthread).setOnClickListener(this);
        findViewById(R.id.backgroundthread).setOnClickListener(this);
        findViewById(R.id.async).setOnClickListener(this);
    }


@Override
protected void onPause() {
super.onPause();

// 注销事件响应
eventBus.unregister(this);
}


@Override
protected void onResume() {
super.onResume();

// 注册事件响应
eventBus.register(this);
}


@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.postthread:

// 抛出PostThread模式的LoadButtonEvent事件
eventBus.post(loadButtonList("postthread", 30));
break;
case R.id.mainthread:

// 抛出MainThread模式的LoadLineEvent事件
eventBus.post(loadLineList(20));
break;
case R.id.backgroundthread:

// 抛出BackgroundThread模式的LoadNoneEvent事件
eventBus.post(new LoadNoneEvent());
break;
case R.id.async:

// 抛出Async模式的LoadAsyEvent事件
eventBus.post(new LoadAsyEvent());
break;
default:
break;
}
}
    
public LoadEvent loadTextList(String str, int num) {
ArrayList<TextView> list = new ArrayList<TextView>(num);
for (int i = 0; i < num; i++) {
TextView textView = new TextView(this);
textView.setText(str + i);
list.add(textView);
}
return new LoadEvent(list);
}

public LoadLineEvent loadLineList(int num) {
ArrayList<View> list = new ArrayList<View>();
for (int i = 0; i < num; i++) {
View view = new View(this);
view.setBackgroundColor(Color.BLUE);
list.add(view);
}
return new LoadLineEvent(list);
}

public LoadButtonEvent loadButtonList(String str, int num) {
ArrayList<Button> list = new ArrayList<Button>();
for (int i = 0; i < num; i++) {
Button button = new Button(this);
button.setText(str + i);
list.add(button);
}
return new LoadButtonEvent(list);
}

// 以PostThread的方式接受LoadButtonEvent事件
public void onEvent(LoadButtonEvent event) {
Log.d("EventBus", "load post thread");
addButtonViews(event);
}

// 以MainThread的方式接受LoadLineEvent事件
public void onEventMainThread(LoadLineEvent event) {
Log.d("EventBus", "load main thread");
addLineViews(event);
}

// BackgroundThread的方式接受LoadNoneEvent事件
public void onEventBackgroundThread(LoadNoneEvent event) {
Log.d("EventBus", "load background thread");
LoadEvent loadE = loadTextList("backgroundthread", 500);

// 抛出MainThread模式的LoadEvent事件用来更新界面
eventBus.post(loadE);
}

// 以Async的方式接受LoadAsyEvent事件
public void onEventAsync(LoadAsyEvent event) {
Log.d("EventBus", "load async");
LoadEvent loadE = loadTextList("async", 1000);

// 抛出MainThread模式的LoadEvent事件用来更新界面
eventBus.post(loadE);
}

// 以MainThread的方式接受LoadEvent事件
public void onEventMainThread(LoadEvent event) {
addTextViews(event);
}

private void addLineViews(LoadLineEvent event) {
viewGroup.removeAllViews();
for (View view : event.list) {
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, 20);
viewGroup.addView(view, param);
}
}

private void addButtonViews(LoadButtonEvent event) {
viewGroup.removeAllViews();
for (Button button : event.list) {
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
viewGroup.addView(button, param);
}
}

private void addTextViews(LoadEvent event) {
viewGroup.removeAllViews();
for (TextView view : event.list) {
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
viewGroup.addView(view, param);
}
}

class LoadEvent {

List<TextView> list;

public LoadEvent(List<TextView> list) {
this.list = list;
}
}

class LoadLineEvent {

List<View> list;

public LoadLineEvent (List<View> list) {
this.list = list;
}
}

class LoadButtonEvent {

List<Button> list;

public LoadButtonEvent(List<Button> list) {
this.list = list;
}
}

class LoadNoneEvent {

}

class LoadAsyEvent {

}
}

界面其实很简单,四个按钮,分别为R.id.postthread,R.id.mainthread,R.id.backgroundthread,R.id.async,这个是分别针对Event Bus中ThreadMode的四种模式:PostThread,MainThread,BackgroundThread,Async。

PostThread —— 直接将事件抛在当前的线程中。

MainThread —— 将事件抛在主线程中(UI线程)。

BackgroundThread —— 将事件抛在新的线程中。

Async —— 将事件抛在异步线程中。


viewGroup是一个在ScrollView下面的LinearLayout布局。


greenrobot Event Bus,其固定的接受事件代码是

public void onEvent(AnyEvent event) -- PostThread

public void onEventMainThread(AnyEvent event) -- MainThread

public void onEventBackgroundThread(AnyEvent event) -- BackgroundThread

public void onEventAsync(AnyEvent event) -- Async

其实还有一种方法,可以直接定义事件接受的方法。

可查看EventBus中的代码 public void register(Object subscriber, String methodName, Class<?> eventType, Class<?>... moreEventTypes)

methodName -- 可以是自己定义的方法名,可以完全取代"onEvent",至于4种模式同样可以区分,methodName只需要前缀,譬如传递的参数是loadEvent,而代码中的方法是public void loadEventAsync(AnyEvent event),则表示是通过Async抛出的事件,以此类推。

Class<?> eventType, Class<?>... moreEventTypes -- 是于事件相关的一些参数。

也可以通过阅读EventBus的源码来获取更多的信息。

在BackgroundThread,Async模式中,最后如果要刷新界面的话,他们还是需要在以MainThread的模式抛出刷新界面的事件。

greenrobot Event Bus下载地址:https://github.com/greenrobot/EventBus


接着介绍guava Event Bus,

package com.benny.test;


import java.util.concurrent.Executor;


import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;


import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;


public class GuavaEventBusDemoActivity extends Activity implements OnClickListener {

// 创建异步的EventBus
private EventBus asyBus = new AsyncEventBus(new Executor() {

private Handler mHandler;
 

// 实现异步机制的事件处理
@Override
public void execute(Runnable command) {
if (mHandler == null) {
mHandler = new Handler(Looper.getMainLooper());
}
mHandler.post(command);
}

});
private EventBus bus = new EventBus();
private LinearLayout viewGroup;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        viewGroup = (LinearLayout)findViewById(R.id.main_layout);
        findViewById(R.id.postthread).setOnClickListener(this);
        findViewById(R.id.mainthread).setOnClickListener(this);
        findViewById(R.id.backgroundthread).setOnClickListener(this);
        findViewById(R.id.async).setOnClickListener(this);
    }
    
@Override
protected void onPause() {
super.onPause();

// 注销事件订阅者
bus.unregister(this);
asyBus.unregister(this);
}


@Override
protected void onResume() {
super.onResume();

// 注册事件订阅者
bus.register(this);
asyBus.register(this);
}




@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.postthread:
break;
case R.id.mainthread:

// 主线程抛LoadButtonEvent事件
bus.post(new LoadButtonEvent("main thread", 100));
break;
case R.id.backgroundthread:
break;
case R.id.async:

// 异步线程抛LoadTextEvent事件
asyBus.post(new LoadTextEvent("async", 1000));
break;
default:
break;
}
}

// 订阅LoadButtonEvent事件处理
@Subscribe
public void loadButtonList(LoadButtonEvent event) {
Log.d("Guava", "ButtonEvent" + event);
viewGroup.removeAllViews();
for (int i = 0; i < event.num; i++) {
Button button = new Button(this);
button.setText(event.str + i);
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
viewGroup.addView(button, param);
}
}

// 订阅LoadTextEvent事件处理
@Subscribe
public void loadTextListAsync(LoadTextEvent event) {
Log.d("Guava", "TextEvent=" + event.str);
viewGroup.removeAllViews();
for (int i = 0; i < event.num; i++) {
TextView textView = new TextView(this);
textView.setText(event.str + i);
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
viewGroup.addView(textView, param);
}
}

class LoadButtonEvent {
String str;
int num;

public LoadButtonEvent(String str, int num) {
this.str = str;
this.num = num;
}
}

class LoadTextEvent {
String str;
int num;

public LoadTextEvent(String str, int num) {
this.str = str;
this.num = num;
}
}

}

界面跟上一个实例是一样的,不过只用到了2个按钮,MainThread和Async按钮,viewGroup是一个在ScrollView下面的LinearLayout布局。

异步的关键就在于

private EventBus asyBus = new AsyncEventBus(new Executor() {

private Handler mHandler;
 

// 实现异步机制的事件处理
@Override
public void execute(Runnable command) {
if (mHandler == null) {
mHandler = new Handler(Looper.getMainLooper());
}
mHandler.post(command);
}

});

这样可以直接在异步事件后刷新界面。

guava Event Bus 下载地址:https://code.google.com/p/guava-libraries/


综合以上2个实例,这两种Event Bus的各自优点也很明显,greenrobot Event Bus有四种模式抛出事件,guava Event Bus的异步实现比greenrobot来的方便,无需再抛MainThread事件了。源码就不上了,大家动手写写可以加深印象。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。