LocalBroadcastManager
-
单例获取LocalBroadcastManager实体,dooublecheck
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this)
-
注册广播接收者,
lbm.registerReceiver(mrevicer, new IntentFilter("LOCAL_ACTION"));
构建一个广播信息实体ReceiverRecord entry = new ReceiverRecord(filter, receiver)到ArrayList中
最后action的string做key,包含ReceiverRecord 的ArrayList做value放入HashMap mActions 中mActions.put(action, entries)
-
发生广播
lbm.sendBroadcast(new Intent().setAction("LOCAL_ACTION").putExtra("text","ni shi local"));
从mActions中获取广播匹配"LOCAL_ACTION"的实体ReceiverRecord的集合
循环集合得到ReceiverRecord对每个进行math,把match的结果放入集合mPendingBroadcasts,然后发生message
内部类Handler处理消息调用executePendingBroadcasts()
从集合mPendingBroadcasts中拿到每个receiver调用receiver.onReceive(mAppContext, br.intent)filter.match(action, type, scheme, data, categories, "LocalBroadcastManager")
-
取消广播
从mActions中取出对应action的集合
然后有当前对象,就从集合中移除lbm.unregisterReceiver(mrevicer);
优点比全局广播效率高,
缺点,使用Android原生API,不适合javalib,LocalBroadcastManager的传递不方便需要context不是所有module都有context对象,组件化能用但是不适合
EventBus
EventBus可以代替Android传统的Intent,Handler,Broadcast或接口函数,在Fragment,Activity,Service线程之间传递数据,只是传递。Handler是很多时候逃不掉的坑。
register
通过getDefault获取EventBus实例,这是一条默认的事件总线,通过单例模式实现,其构造函数是Public的,也可以通过EventBus.builder().build()来创建多条事件总线,一般在oncreate中创建。
EventBus.getDefault().register(this);
//这是一个构建者模式+链式调用,build之前可以链式调用添加参数
EventBus.builder().build()
unregister
如果是默认直接通过下面的方法取消,自己新建的就要拿到之前保留的对象,然后调用unregister方法
EventBus.getDefault().unregister(this);
post
发送消息,可以是任意对象。
EventBus.getDefault().post(daLaBa);
Subscribe
- threadMode
-
POSTING
默认的模式,开销最小的模式,因为声明为POSTING的订阅者会在发布的同一个线程调用,发布者在主线程那么订阅者也就在主线程,反之亦,避免了线程切换,如果不确定是否有耗时操作,谨慎使用,因为可能是在主线程发布 -
MAIN
主线程调用,视发布线程不同处理不同,如果发布者在主线程那么直接调用(非阻塞式),如果发布者不在主线程那么阻塞式调用 -
MAIN_ORDERED
和MAIN差不多,主线程调用,和MAIN不同的是他保证了post是非阻塞式的(默认走MAIN的非主线程的逻辑,所以可以做到非阻塞) -
BACKGROUND
在子线程调用,如果发布在子线程那么直接在发布线程调用,如果发布在主线程那么将开启一个子线程来调用,这个子线程是阻塞式的,按顺序交付所有事件,所以也不适合做耗时任务,因为多个事件共用这一个后台线程 -
ASYNC
在子线程调用,总是开启一个新的线程来调用,适用于做耗时任务,比如数据库操作,网络请求等,不适合做计算任务,会导致开启大量线程
-
流程
register
-
获得传入对象的类对象。
-
获得这个类中定义的订阅函数。
subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//subscriberClass传入对象的class-
从缓存中取出METHOD_CACHE订阅方法集合。如果有直接返回。
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
-
如果缓存中没有,选择合适的方法寻找订阅方法。
subscriberMethods = findUsingReflection(subscriberClass);直接通过反射查找
subscriberMethods = findUsingInfo(subscriberClass);默认查找
两者区别第二个多出从subscriberMethodFinder.subscriberInfoIndexes中获取SubscriberInfoIndex来获取SubscriberInfo-
从状态池获得一个状态对象。
FindState findState = prepareFindState -
将订阅者类传入,设置一些状态对象的参数。
findState.initForSubscriber(subscriberClass); -
通过状态对象寻找订阅者信息,如果找到就获取到了订阅方法数组,并循环检测合法性,通过findState.subscriberMethods.add(subscriberMethod)放入其集合中。
// 寻找方法findState.subscriberInfo = getSubscriberInfo(findState); // 这一步就是多出来的通过subscriberMethodFinder.subscriberInfoIndexes的索引缓存查找
-
如果没有没有找到订阅者信息,则调用方法,用反射去寻找订阅方法。
findUsingReflectionInSingleClass(findState);- 获取订阅类中定义的方法。(方法类型、方法参数长度之类)
- 遍历方法集合,检测完合法性,将合法的订阅方法封装,存入状态对象
Class<?> eventType = parameterTypes[0] findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
-
状态对象指向父类,再次循环,找父类中的订阅方法。
findState.moveToSuperclass(); -
返回subscriberMethods,并且回收findState
return getMethodsAndRelease(findState)
-
-
如果没有找到订阅方法,抛出异常程序崩溃。
如果找到了订阅方法,将它和订阅者类对象组成键值对存储到缓存METHOD_CACHE。METHOD_CACHE.put(subscriberClass, subscriberMethods);
-
-
对每个订阅函数进行订阅操作。
-
根据订阅方法获取事件类型。
Class<?> eventType = subscriberMethod.eventType;
-
将订阅者和订阅方法组合成一个订阅对象。
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
-
获取订阅对象集合,如果为空直接新建集合后放入,
将订阅对象集合中对象按优先级排序后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); } } int size = subscriptions.size(); for (int i = 0; i <= size; i++) { if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; } }
-
根据注册方法传入的对象获取到它可以相应的事件类型集合,
如果没有新建一个集合,将对象做key,集合做value存Map typesBySubscriber当中。
最后都会将事件类型存入集合//根据订阅者获取事件类型集合 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); //没有存储过事件类型,新建一个集合 if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } //put当前事件类型进去 subscribedEvents.add(eventType);
-
处理粘性事件。如果之前有粘性事件,则取出并发送给订阅者
-
post
使用ThreadLocal来存储事件,他可以隔离多个线程对数据的访问冲突
-
获得post线程状态对象。
PostingThreadState postingState = currentPostingThreadState.get();
-
从这个线程状态对象中取得事件队列。加入事件对象。
List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event);
-
如果事件没有在分发中,
-
设置分发状态和是否主线程。
-
循环取出事件队列中的事件进行分发过程。
while (!eventQueue.isEmpty()) { postSingleEvent(eventQueue.remove(0), postingState); }
找到我们自定义事件类型的类对象。
--->eventInheritance若为true,会找到这个事件类型的自身和父类,逐一进行事件分发。
--->eventInheritance为true,只对自身事件类型进行分发。
--->最终都会通过下面的postSingleEventForEventType分发subscriptionFound = postSingleEventForEventType(event, postingState, eventClass)
-
根据事件类型获得订阅对象集合。
1. subscriptions = subscriptionsByEventType.get(eventClass);
-
如果集合不为空,循环subscriptions集合
将event和subscription给赋值postingState的属性
调用postToSubscription(subscription, event, postingState.isMainThread);
赋值aborted = postingState.canceled;
然后重置postingState
postingState.event = null; postingState.subscription = null; postingState.canceled = false;
如果aborted = ture跳槽循环
-
根据threadMode找到合适的线程来调用订阅函数而已
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { //根据订阅方法注解中标明的执行线程执行 switch (subscription.subscriberMethod.threadMode) { case POSTING: invokeSubscriber(subscription, event); break; case MAIN: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; case BACKGROUND: if (isMainThread) { backgroundPoster.enqueue(subscription, event); } else { invokeSubscriber(subscription, event); } break; case ASYNC: asyncPoster.enqueue(subscription, event); break; default: throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode); } }
**主线程mainThread: **
Poster:通过继承Handler重写handleMessage增加新的enqueue方法
enqueue方法:加入自己的队列,发送空消息
handleMessage:invokeSubscriber(subscription, event)省略了很多逻辑
**backgroundPoster: **
enqueue方法:加入自己的队列,如果第一次启动线程就传入自己(实现了Runnable)然后启动线程
run方法:无限循环,从队列取pendingPost,然后调用eventBus.invokeSubscriber(pendingPost)
**asyncPoster: **
enqueue方法:加入自己的队列,启动线程传入自己(实现了Runnable)
run方法:从队列取pendingPost,然后调用eventBus.invokeSubscriber(pendingPost)
eventBus.invokeSubscriber(pendingPost):
method.invoke(subscription.subscriber, event):
-
-
返回flase
-
通过postToSubscription向订阅者进行事件分发。
接下来调用postToSubscription继续实际分发。
如果都没有就发送没有订阅者的事件post(new NoSubscriberEvent(this, event));
-
-
-
重置postingState
postingState.isPosting = false; postingState.isMainThread = false;
unregister
根据传入对象找到订阅的事件类型集合,
for循环事件集合
从subscriptionsByEventType获取subscriptions集合
如何subscription.subscriber == subscriber(传入的对象)就从subscriptions集合移出
Rxbus
是基于Rxjava的一种封装要比EventBus好,因为效率高,线程调度和链式优于Eventbus
ModuleBus
跟Eventbus类似,能传递基础数据类型。自定义的事件信息模型还是要添加到BaseModule中才能让其他模块引用
ModularizationArchitecture
是一个路由带事件功能,已经停工了,需要context,使用场景有限,不多说。
LocalRouter.getInstance()
组件化中使用总线怎么办
可以抽离成一个单独的模块,让BaseModule依赖,把事件抽离到XXXBusModule,来解耦,减少对BaseModule的影响。
网友评论