EventBus使用
来源:互联网 发布:mac怎么新建txt文件 编辑:程序博客网 时间:2024/06/05 15:05
EventBus 是一种为 Android 而优化设计的发布/订阅事件总线
有了这个,对于一个事件,你只要关心发送和接收就行了,而其中的收集、分发等都交给 EventBus 来处理,你不需要做任何事
使用方法
首先导入依赖包
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'org.greenrobot:eventbus:3.0.0' testCompile 'junit:junit:4.12'}第一步,定义一个事件类MyEvent
public class MyEvent { private String msg;//需要传递的数据(可以是复杂bean对象) public MyEvent(String msg) { this.msg = msg; } public String getMsg() { return msg; }}
定义一个订阅方法,可以使用 @Subscribe 注解来指定订阅方法所在的线程:
@Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MyEvent event) { String msg=event.getMsg();//获取传递过来的信息 };
注册和反注册你的订阅方法。比如在 Android 中,Activity 和 Fragment 通常在如下的生命周期中进行注册和反注册:
@Overridepublic void onStart() { super.onStart(); EventBus.getDefault().register(this);}@Overridepublic void onStop() { super.onStop(); EventBus.getDefault().unregister(this);}
3.发送事件:
EventBus.getDefault().post(new MyEvent("msg"));
使用非常简单
EventBus 原理分析
EventBus.getDefault()
来看源码
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder(); private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; private final Map<Object, List<Class<?>>> typesBySubscriber; private final Map<Class<?>, Object> stickyEvents; public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; } /** * Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a * central bus, consider {@link #getDefault()}. */ public EventBus() { this(DEFAULT_BUILDER); } EventBus(EventBusBuilder builder) { // key 为事件的类型,value 为所有订阅该事件类型的订阅者集合 subscriptionsByEventType = new HashMap<>(); // key 为某个订阅者,value 为该订阅者所有的事件类型 typesBySubscriber = new HashMap<>(); // 粘性事件的集合,key 为事件的类型,value 为该事件的对象 stickyEvents = new ConcurrentHashMap<>(); // 主线程事件发送者 mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); // 子线程事件发送者 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); // 是否打印订阅者异常的日志,默认为 true logSubscriberExceptions = builder.logSubscriberExceptions; // 是否打印没有订阅者的异常日志,默认为 true logNoSubscriberMessages = builder.logNoSubscriberMessages; // 是否允许发送 SubscriberExceptionEvent ,默认为 true sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; // 是否允许发送 sendNoSubscriberEvent ,默认为 true sendNoSubscriberEvent = builder.sendNoSubscriberEvent; // 是否允许抛出订阅者的异常,默认是 false throwSubscriberException = builder.throwSubscriberException; // 是否支持事件继承,默认是 true eventInheritance = builder.eventInheritance; // 创建线程池 executorService = builder.executorService; }
平时的我们经常调用的 EventBus.getDefault() 代码,其实是获取了 EventBus 类的单例。在初始化这块调用的是EventBusBuilder的默认参数,在 EventBus 构造器中初始化了一堆的成员变量.
EventBus.register(Object subscriber)
事件订阅者必须调用 register(Object subscriber) 方法来进行注册,一起来看看在 register(Object subscriber) 中到底做了一些什么:
public void register(Object subscriber) { // 得到订阅者的类 class Class<?> subscriberClass = subscriber.getClass(); // 找到该 class 下所有的订阅方法 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }在 register(Object subscriber) 中,利用 subscriberMethodFinder.findSubscriberMethods 方法找到订阅者 class 下所有的订阅方法,然后用 for 循环建立订阅关系。
然后就是轮到了 subscribe(subscriber, subscriberMethod) 方法:
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { // 得到订阅方法的事件类型 Class<?> eventType = subscriberMethod.eventType; Subscription newSubscription = new Subscription(subscriber, subscriberMethod); // 根据订阅方法的事件类型得到所有订阅该事件类型的订阅者集合 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); subscriptionsByEventType.put(eventType, subscriptions); } else { // 如果 subscriptions 已经包含了,抛出异常 if (subscriptions.contains(newSubscription)) { throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } } // 根据该 subscriberMethod 优先级插入到 subscriptions 中 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; } } // 放入 subscribedEvents 中,key:订阅者 value:该订阅者的所有订阅事件的类型 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); // 如果订阅的方法支持 sticky if (subscriberMethod.sticky) { // 如果支持事件继承 if (eventInheritance) { // Existing sticky events of all subclasses of eventType have to be considered. // Note: Iterating over all events may be inefficient with lots of sticky events, // thus data structure should be changed to allow a more efficient lookup // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>). Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet(); // 遍历 stickyEvents for (Map.Entry<Class<?>, Object> entry : entries) { Class<?> candidateEventType = entry.getKey(); // 判断 eventType 类型是否是 candidateEventType 的父类 if (eventType.isAssignableFrom(candidateEventType)) { // 得到对应 eventType 的子类事件,类型为 candidateEventType Object stickyEvent = entry.getValue(); // 发送粘性事件给 newSubscription checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } } else { // 拿到之前 sticky 的事件,然后发送给 newSubscription Object stickyEvent = stickyEvents.get(eventType); // 发送粘性事件给 newSubscription checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } }
其实 subscribe(subscriber, subscriberMethod) 方法主要就做了三件事:
得到 subscriptions ,然后根据优先级把 subscriberMethod 插入到 subscriptions 中;
将 eventType 放入到 subscribedEvents 中;
如果订阅方法支持 sticky ,那么发送相关的粘性事件。
unregister(Object subscriber)首先从typesBySubscriber获取当前订阅者,然后找到此订阅者的所有类型,将此订阅者的所有类型从subscriptionsByEventType表里删除。接着再把此订阅者从typesBySubscriber中删除
看看 unregister(Object subscriber) 的源码:
public synchronized void unregister(Object subscriber) { // 通过 subscriber 来找到 subscribedTypes List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null) { for (Class<?> eventType : subscribedTypes) { // 解除每个订阅的事件类型 unsubscribeByEventType(subscriber, eventType); } // 从 typesBySubscriber 中移除 typesBySubscriber.remove(subscriber); } else { Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } } private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { int size = subscriptions.size(); for (int i = 0; i < size; i++) { Subscription subscription = subscriptions.get(i); if (subscription.subscriber == subscriber) { subscription.active = false; subscriptions.remove(i); i--; size--; } } } }
post(Object event)分析下发送事件 post(Object event) 的源码:
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); } }; public void post(Object event) { // 得到当前线程的 postingState PostingThreadState postingState = currentPostingThreadState.get(); // 加入到队列中 List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event); // 如果没有持续在发送事件,那么开始发送事件并一直保持发送ing if (!postingState.isPosting) { postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper(); postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); } try { while (!eventQueue.isEmpty()) { // 发送单个事件 postSingleEvent(eventQueue.remove(0), postingState); } } finally { postingState.isPosting = false; postingState.isMainThread = false; } } }在 post(Object event) 中,首先根据 currentPostingThreadState 获取当前线程状态 postingState 。currentPostingThreadState 其实就是一个 ThreadLocal 类的对象,不同的线程根据自己独有的索引值可以得到相应属于自己的 postingState 数据。然后把事件 event 加入到 eventQueue 队列中排队。只要 eventQueue 不为空,就不间断地发送事件EventBus 是一款典型的运行观察者模式的开源框架,设计巧妙,代码也通俗易懂,值得我们学习。
- EventBus 使用
- EventBus使用
- eventbus使用
- EventBus使用
- EventBus---使用
- EventBus使用
- EventBus 使用
- EventBus使用
- EventBus使用
- EventBus使用
- EventBus使用
- EventBus使用
- EventBus使用
- EventBus使用
- EventBus使用
- EventBus使用
- EventBus使用
- EventBus使用
- Android 设计模式
- Java初级入门
- NS2整体实现机制(转)
- 解决滑动条控件,子物体减少,滑动条不刷新的bug
- Java面试题二:基础语法(续面试题一)
- EventBus使用
- spring 底层实现IOC DI简单依赖反射
- mysql安装与基本操作
- 隐藏QT窗口在任务栏中的图标
- Guava ListenableFuture 实现多线程 先执行完线程任务 ,再来执行主线程
- 运输问题--替换型贪心
- mybatis查询sql:where语句“查询时间字段书写问题”引发的索引失效
- Logo
- Web前端高效开发总结二:HTML最佳实践