Eventbus的使用与原理解析

简单使用:
首先依赖eventbus
api ‘org.greenrobot:eventbus:3.2.0’
使用的方式很简单

在activity或者fragment中注册
EventBus.getDefault().register(this);
别忘记最后接触注册
EventBus.getDefault().unregister(this);
发送消息
EventBus.getDefault().post(msg)
接收消息
@Subscribe
public void  getMsg(EventMessage msg){
 }

这样eventbus就可以使用了接下来分析原理,按照上面的使用步骤挨个分析:首先分析注册的原理:

方法一
public void register(Object subscriber) {
	1.获取订阅的class类型对象
    Class<?> subscriberClass = subscriber.getClass();
    2.获取当前class类对象所订阅的方法集合查看方法二
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
    3.遍历所有的方法合集,订阅事件 查看方法三
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

方法二

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
首先先从METHOD_CACH中获取,如果有直接返回,不执行接下来的方法
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) {
        return subscriberMethods;
    }

    if (ignoreGeneratedIndex) {
    这块如果自定义了EventBusBuilder,就走这块不是我们关注的重点
        subscriberMethods = findUsingReflection(subscriberClass);
    } else {
    主要看这块
        subscriberMethods = findUsingInfo(subscriberClass);
    }
    if (subscriberMethods.isEmpty()) {
        throw new EventBusException("Subscriber " + subscriberClass
                + " and its super classes have no public methods with the @Subscribe annotation");
    } else {
        METHOD_CACHE.put(subscriberClass, subscriberMethods);
        return subscriberMethods;
    }
}
接下来看这个方法
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
// FindState辅助我们查找订阅方法的类,
    FindState findState = prepareFindState();
    //将我们订阅的类传递进去
    findState.initForSubscriber(subscriberClass);
    //findState.clazz就是上面initForSubscriber传递进去的类
    while (findState.clazz != null) {
    //获取我们订阅类的订阅方法信息
        findState.subscriberInfo = getSubscriberInfo(findState);
        //第一次为空
        if (findState.subscriberInfo != null) {
            SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
            for (SubscriberMethod subscriberMethod : array) {
                if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                    findState.subscriberMethods.add(subscriberMethod);
                }
            }
        } else {
        //直接看这里
            findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();
    }
    // 将查找到的方法保存在了FindState实例的subscriberMethods集合中。然后使用subscriberMethods构建一个新的List<SubscriberMethod>并返回,最后释放掉findState
    return getMethodsAndRelease(findState);
}
/**
 * 作用:通过反射获取订阅方法的信息
 */
private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
        // This is faster than getMethods, especially when subscribers are fat classes like Activities
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
        // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
        try {
            methods = findState.clazz.getMethods();
        } catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad...
            String msg = "Could not inspect methods of " + findState.clazz.getName();
            if (ignoreGeneratedIndex) {
                msg += ". Please consider using EventBus annotation processor to avoid reflection.";
            } else {
                msg += ". Please make this class visible to EventBus annotation processor to avoid reflection.";
            }
            throw new EventBusException(msg, error);
        }
        findState.skipSuperClasses = true;
    }
    //便利反射
  for (Method method : methods) {
        int modifiers = method.getModifiers();
        //方法是public类型,但非abstract、static等
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
            Class<?>[] parameterTypes = method.getParameterTypes();
            //参数必须只有一个
            if (parameterTypes.length == 1) {
                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                if (subscribeAnnotation != null) {
           e     // 获取该订阅方法上的第一个参数类型,也就是订阅的事件类型这个evnettype很重要,在之后会多次见到
                    Class<?> eventType = parameterTypes[0];
                      // checkAdd()方法用来判断FindState中是否已经添加过将该事件类型为key的键值对,没添加过则返回true
                    if (findState.checkAdd(method, eventType)) {
                    // 将该订阅方法,事件类型,线程模式,优先级,是否支持粘性事件等信息,封装成SubscriberMethod对象,并添加到findState中的subscriberMethods集合里
                        ThreadMode threadMode = subscribeAnnotation.threadMode();
                        findStated.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                    }
                }
            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException("@Subscribe method " + methodName +
                        "must have exactly 1 parameter but has " + parameterTypes.length);
            }
        } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
            String methodName = method.getDeclaringClass().getName() + "." + method.getName();
            throw new EventBusException(methodName +
                    " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
        }
    }
}
接下来方法三
/**
 * 开始订阅
 * subscriberMethod封装了当前方法的threadMode、eventType等
 * eventType 订阅事件的参数class对象
 * Subscription 以订阅类的class对象和SubscriberMethod 封装成的新对象
 * 以eventType 为key,ArrayList<Subscription>为value的map
 * typesBySubscriber以当前订阅的clas对象为key,list<eventType> 为值的map集合
 *  */
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//获取参数的class对象l类型
    Class<?> eventType = subscriberMethod.eventType;
    //订阅的类对象和subscriberMethod构造成新的对象
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    //获取以eventType 为key的所有的Subscription对象
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions == null) {
   	//没有创建,并添加subscriptionsByEventType
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
    	//有看一下是否包含
        if (subscriptions.contains(newSubscription)) {
            throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                    + eventType);
        }
    }
    // 添加上边创建的newSubscription对象到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;
        }
    }
  // typesBySubscriber也是一个HashMap,保存了以当前要订阅类的对象为keyd订阅类中参数类型的集合为value的键值对
    // 和上面一样,根据key先判断,是否已经存储过了,如果已经存储过了,直接取出订注册类中订阅事件的方法的参数
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.pu t(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);
	//判断s是否粘性事件
    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();
            for (Map.Entry<Class<?>, Object> entry : entries) {
                Class<?> candidateEventType = entry.getKey();
                if (eventType.isAssignableFrom(candidateEventType)) {
                    Object stickyEvent = entry.getValue();
                    checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                }
            }
        } else {
            Object stickyEvent = stickyEvents.get(eventType);
            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
        }
    }
}

简单总结下:
传入需要订阅类信息,根据反射获取类上的所有方法,遍历这些方法,取出其中的订阅方法(条件是,一个参数,权限为public,使用了Subscribe标签)将方法的信息封装成SubscriberMethod对象,并存入集合,然后再遍历这个集合,将出其中的SubscriberMethod对象以及当前订阅的class对象,合并成Subscription对象,然后根据eventtype类型,进行重新分类,存入map subscriptionsByEventType中(key 为eventtype, value 为List),再创建一个map typesBySubscriber, 以当前订阅的clas对象为key , list为value。 简单来说根据map typesBySubscriber就可以获取到当前订阅的页面所有参数类型的方法,然后再根据map subscriptionsByEventType以当前方法参数类型,获取到所有的Subscription对象,这样就建立了联系。
有了上面的注册接下来看解除注册

/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
//获取当前订阅类页面所有的不同的eventtype的list,因为一个页面通常可能有很多订阅的事件参数也不一样
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
    //便利这个list,解除订阅
        for (Class<?> eventType : subscribedTypes) {
        //方法四
            unsubscribeByEventType(subscriber, eventType);
        }
        typesBySubscriber.remove(subscriber);
    } else {
        logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}
/**
方法四
上面的方法已经获取到订阅页面所有的不同参数类型class对象然后根据这个对象,从subscriptionsByEventTypeq取出Subscription对象,判断Subscription的subscriber是否相同,相同移除。同样的参数类型也可能在多个页面注册,所有有多个,要找到当订阅对象的移除
 */
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
//获取该页面当前eventtpe所对应的list集合遍历
    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--;
            }
        }
    }
}

解除绑定,其实比较简单,主要就是运用注册时所产生的2个map, 先根据typesBySubscriber,也就是根据要解除绑定的注册类,找到这个类所拥有的所有订阅事件,然后遍历这些订阅事件,再根据这些订阅事件,在subscriptionsByEventType中找到,这个事件所对应的订阅方法的集合,再遍历集合,判断该订阅方法的注册类信息,是否是要解除绑定的注册类,如果是,移除该订阅方法信息,完成解除绑定。
接下来看post方法

public void post(Object event) {
//currentPostingThreadState就是个ThreadLocal可参考我的文章线 PostingThreadState 当前线程独有的,线程安全https://blog.csdn.net/m0_37777069/article/details/108768945
    PostingThreadState postingState = currentPostingThreadState.get();
     // 获取postingState里面存的一个队列
    List<Object> eventQueue = postingState.eventQueue;
    eventQueue.add(event);
	// 判断该事件是否正在发送,如果在发送,则跳过下面的逻辑
    if (!postingState.isPosting) {
        postingState.isMainThread = isMainThread();
        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;
        }
    }
}
//方法五
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
//对应的上面eventtype的类对象
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;
        // 是否要查看所有的继承关系
    if (eventInheritance) {
        List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
        int countTypes = eventTypes.size();
        for (int h = 0; h < countTypes; h++) {
            Class<?> clazz = eventTypes.get(h);
            subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
        }
    } else {
    //如果定义的发送消息事件没有弗雷直接走postSingleEventForEventType
    //方法六
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
    }
    //如果没有匹配发送事件的类型,
    if (!subscriptionFound) {
        if (logNoSubscriberMessages) {
            logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
        }
        if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                eventClass != SubscriberExceptionEvent.class) {
            post(new NoSubscriberEvent(this, event));
        }
    }
}
//方法六
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
    CopyOnWriteArrayList<Subscription> subscriptions;
    synchronized (this) {
    //熟悉吧,根据参数类型获取Subscription对象,
        subscriptions = subscriptionsByEventType.get(eventClass);
    }
    //不为空则遍历
    if (subscriptions != null && !subscriptions.isEmpty()) {
        for (Subscription subscription : subscriptions) {
            postingState.event = event;
            postingState.subscription = subscription;
            boolean aborted;
            try {
          //方法七这时候就已经取到该事件接收的页面以及方法了
                postToSubscription(subscription, event, postingState.isMainThread);
                aborted = postingState.canceled;
         f   } finally {
                postingState.event = null;
                postingState.subscription = null;
                postingState.canceled = false;
            }
            if (aborted) {
                break;
            }
        }
        return true;
    }
    return false;
}

//方法七根据订阅事件的消息模式来执行具体的事件 isMainThread是指当前发送事件的线程
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 MAIN_ORDERED:
            if (mainThreadPoster != null) {
                mainThreadPoster.enqueue(subscription, event);
            } else {
                // temporary: technically not correct as poster not decoupled from subscriber
                invokeSubscriber(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);
    }
}
//方法八直接通过反射执行相应的方法
void invokeSubscriber(Subscription subscription, Object event) {
    try {
        subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
    } catch (InvocationTargetException e) {
        handleSubscriberException(subscription, event, e.getCause());
    } catch (IllegalAccessException e) {
        throw new IllegalStateException("Unexpected exception", e);
    }
}
//方法九其实就是通过handler切换线程实现执行任务
public class HandlerPoster extends Handler implements Poster {

    private final PendingPostQueue queue;
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    private boolean handlerActive;

    protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);
        this.eventBus = eventBus;
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

    @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            handlerActive = false;
                            return;
                        }
                    }
                }
                eventBus.invokeSubscriber(pendingPost);
                long timeInMethod = SystemClock.uptimeMillis() - started;
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
}

这样基本一个事件从页面注册,到发送,整个流程就分析完了,总的来说还是很简单的,只要耐心看完,希望你有所收获

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值