(一)介绍
1,EvenetBus是一种发布-订阅事件总线.
代码简洁,开销小,并很好的实现了发送者和接收者的解耦.(是一种观察者模式)
2,三要素:
3,通常情况下安卓下数据的传递有下面几种方法:
3.1.通过intent传递,包括显式意图和隐式意图,广播(Broadcast)和服务都能通过Intent传递
传递的数据类型包括8大基本数据类型 实现Parcelable或Serializable接口的类型 以及集合数组类型
3.2.静态变量传递 在工具类下 声明一个Object类型的静态变量 在A中将要传递的值,在B中通过这个静态变量取出来
3.3.通过handle在不同的线程中传递Object类型的数据
3.4.通过构造方法传递Object类型的数据
3.5.通过SharedPreferences传递八大基本数据类型
3.6.通过ContentProvider在进程间共享数据
3.7.通过aidl在进程进程传递数据
3.8.通过流(本地文件)传递八大基本数据类型和实现Serializable接口的数据类型
3.9.通过基类中的属性或者方法
属性: 基类公有属性 在某个子类中赋值 其他子类中都能使用
方法: 子类调用父类的某个方法给父类某个属性赋值 另外一个子类通过父类的另一个公有方法获取这个值(这个方法把值返回)
(二)基本使用
先订阅,后发布
1,添加依赖
compile 'org.greenrobot:eventbus:3.1.1'
2,注册事件
public class MessageEvent {
private String message;
public MessageEvent(String message){
this.message = message;
}
public String getMessage(){
return message;
}
}
3,在接受消息的代码
EventBus.getDefault().register(this);
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent messageEvent){
Log.e("date","receive it");
Toast.makeText(ViewPageStep1Activity.this, messageEvent.getMessage(), Toast.LENGTH_SHORT).show();
}
4,在发送消息的地方
EventBus.getDefault().post(new MessageEvent("从fragment将数据传递到activity22222222"))
先发布,再订阅,黏性事件
5,在接受消息的代码
EventBus.getDefault().register(this);
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Subscribe(threadMode = ThreadMode.MAIN,stick = true)
public void onEvent(MessageEvent messageEvent){
Log.e("date","receive it");
Toast.makeText(ViewPageStep1Activity.this, messageEvent.getMessage(), Toast.LENGTH_SHORT).show();
}
6,在发送消息的地方
EventBus.getDefault().postSticky(new MessageEvent("从fragment将数据传递到activity22222222"))
(三)四个订阅方法
onEvent:
如果使用onEvent作为订阅函数,那么该事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。
onEventMainThread:
如果使用onEventMainThread作为订阅函数,那么不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。
onEventBackground:
如果使用onEventBackgrond作为订阅函数,那么如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。
onEventAsync:
使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync。
(四)源码解析
可以看到,发布者(Publisher)使用post()方法将Event发送到Event Bus,而后Event Bus自动将Event发送到多个订阅者(Subcriber)。这里需要注意两个地方:
(1)一个发布者可以对应多个订阅者。
(2)3.0以前订阅者的订阅方法为onEvent()、onEventMainThread()、onEventBackgroundThread()和onEventAsync()。在Event Bus3.0之后统一采用注解@Subscribe的形式,具体实现方式见下文。
@Subscribe(threadMode = ThreadMode.MAIN)
public void eventBusMain(String str){
Log.i("TAG", "MAIN:"+str+" Thread="+Thread.currentThread().getId());
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void eventBusBg(String str){
Log.i("TAG", "BACKGROUND:"+str+" Thread="+Thread.currentThread().getId());
}
@Subscribe(threadMode = ThreadMode.POSTING)
public void eventBusPosting(String str){
Log.i("TAG", "POSTING:"+str+" Thread="+Thread.currentThread().getId());
}
@Subscribe(threadMode = ThreadMode.ASYNC)
public void eventBusAsync(String str){
Log.i("TAG", "ASYNC:"+str+" Thread="+Thread.currentThread().getId());
}
1,调用getDefault(),里面采用单利双重锁模式创建Eventbus对象
static volatile EventBus defaultInstance;
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
2,构造方法
- 2.1,粘性事件,保存到ConCurrenHashMap集合,(在构造方法中实现),
HashMap效率高,但线程不安全,在多线程的情况下,尽量用ConcurrentHashMap,避免多线程并发异常
EventBus(EventBusBuilder builder) {
logger = builder.getLogger()
subscriptionsByEventType = new HashMap<>()
typesBySubscriber = new HashMap<>()
stickyEvents = new ConcurrentHashMap<>()
mainThreadSupport = builder.getMainThreadSupport()
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null
backgroundPoster = new BackgroundPoster(this)
asyncPoster = new AsyncPoster(this)
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex)
logSubscriberExceptions = builder.logSubscriberExceptions
logNoSubscriberMessages = builder.logNoSubscriberMessages
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent
sendNoSubscriberEvent = builder.sendNoSubscriberEvent
throwSubscriberException = builder.throwSubscriberException
eventInheritance = builder.eventInheritance
executorService = builder.executorService
}
3,注册register()方法主要做了2件事:
- 3.1,找到订阅者的方法.找出传进来的订阅者的所有订阅方法,然后遍历订阅者的方法.
A,通过反射来获取订阅者中所有的方法,并根据方法的类型,参数和注解找到订阅方法.
- 3.2,订阅者的注册
public void register(Object subscriber) {
Class subscriberClass = subscriber.getClass();
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
,并根据方法的类型,参数和注解找到订阅方法.
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;}
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
4,事件发送post(),
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List