2024年Android最新eventbus异步框架源码解析(1),腾讯Android开发面试记录

文末

不管怎么样,不论是什么样的大小面试,要想不被面试官虐的不要不要的,只有刷爆面试题题做好全面的准备,当然除了这个还需要在平时把自己的基础打扎实,这样不论面试官怎么样一个知识点里往死里凿,你也能应付如流啊

小编将自己6年以来的面试经验和学习笔记都整理成了一个**937页的PDF,**以及我学习进阶过程中看过的一些优质视频教程。

其实看到身边很多朋友抱怨自己的工资很低,包括笔者也是一样的,其原因是在面试过程中没有给面试官一个很好的答案。所以笔者会持续更新面试过程中遇到的问题,也希望大家和笔者一起进步,一起学习。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

        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();

    }

    return getMethodsAndRelease(findState);

}



上面代码获取到了订阅集合,下面就是对集合里面的元素进行订阅



// subscriber:订阅者

//subscriberMethod:订阅方法

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {

    Class<?> eventType = subscriberMethod.eventType;

//Subscription封装了订阅者

    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);

    CopyOnWriteArrayList<Subscription> 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);

        }

    }



    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;

        }

    }



    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);

    if (subscribedEvents == null) {

        subscribedEvents = new ArrayList<>();

        typesBySubscriber.put(subscriber, subscribedEvents);

    }

    subscribedEvents.add(eventType);



    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);

        }

    }

}



subscribe方法总结:  

1、首先判断是否注册过该事件,如果注册过,就会抛出异常告诉已经注册了  

2、然后按照优先级加入到subscriptionsByEventType和value的List中  

3、然后添加到typeBySubscriber的value的List中  

4、分发事件:checkPostStickyEventToSubscription



private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {

    if (stickyEvent != null) {

        postToSubscription(newSubscription, stickyEvent, isMainThread());

    }

}

//最后还是用到了3个线程调度的Poster,3个线程调度的Poster是EventBus的核心

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {

    switch (subscription.subscriberMethod.threadMode) {

//POSTING 直接去调用事件

        case POSTING:

            invokeSubscriber(subscription, event);

            break;

// 先判断是否在主线程,在,就会直接调用

//否则通过mainThreadPoster.enqueue将事件发送给主线程执行方法,里面会有一个队列排队的过程,不会阻塞主线程

        case MAIN:

            if (isMainThread) {

                invokeSubscriber(subscription, event);

            } else {

                  //加入队列

                mainThreadPoster.enqueue(subscription, event);

            }

            break;

//mainThreadPoster默认不过null, 所以这种情况下会直接将事件发送给一个队列,然后依次取出,发送给主线程执行,这种情况下不会阻塞主线程

        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);

    }

}



> 四、post发送事件



public void post(Object event) {

//发送的事件都是封装到PendingPost中了,然后存到一个消息队列中

    PostingThreadState postingState = currentPostingThreadState.get();

//获取事件队列集合,并加入到队列当中

    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()) {

//通过保存状态的HashMap找到subscriptions的集合,然后依次遍历去调用postToSubscription方法来发送

                postSingleEvent(eventQueue.remove(0), postingState);

            }

        } finally {

            postingState.isPosting = false;

            postingState.isMainThread = false;

        }

    }

}

//发送事件的线程状态的封装类

final static class PostingThreadState {

//事件队列集合

    final List<Object> eventQueue = new ArrayList<>();

//是否正在发送事件

    boolean isPosting;

//是否在主线程

    boolean isMainThread;

//订阅者封装起来的封装类

    Subscription subscription;

//事件

    Object event;

//是否取消

    boolean canceled;

}

//postSingleEvent方法调用了postSingleEventForEventType

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {

    CopyOnWriteArrayList<Subscription> subscriptions;

    synchronized (this) {

//通过保存状态的HashMap找到subscriptions的集合

        subscriptions = subscriptionsByEventType.get(eventClass);

    }

    if (subscriptions != null && !subscriptions.isEmpty()) {

        for (Subscription subscription : subscriptions) {

            postingState.event = event;

            postingState.subscription = subscription;

            boolean aborted = false;

            try {

//遍历去调用postToSubscription方法来发送

                postToSubscription(subscription, event, postingState.isMainThread);

                aborted = postingState.canceled;

            } finally {

                postingState.event = null;

                postingState.subscription = null;

                postingState.canceled = false;

            }

            if (aborted) {

                break;

            }

        }

        return true;

    }

    return false;

}

//发送消息

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);

    }

}



总结:  

EventBus中最核心的就是线程调度,就是3个Poster:HandlerPoster,BackgroundPoster,AsyncPoster,这3个Poster弄懂了,EventBus也就懂了。



HandlerPoster,BackgroundPoster,AsyncPoster三个Poster都是实现了Poster接口,都是通过enqueue发送 事件,发送的事件都是封装到PendingPost中了,然后存到一个消息队列中



*   HandlerPoster里面封装的是一个Handler,通过sendMessage将事件从子线程发送给主线程

*   BackgroundPoster里面是通过eventBus.getExecutorService().execute执行异步任务,和AsyncPoster不同的是,它执行完异步任务之后,才会去执行下一个任务。

*   AsyncPoster里面是通过eventBus.getExecutorService().execute执行异步任务,和BackgroundPoster不同的是,它每次发送一次事件,都会开一个子线程去执行异步任务。



public class HandlerPoster extends Handler implements Poster {}

final class BackgroundPoster implements Runnable, Poster {}

class AsyncPoster implements Runnable, Poster {}

final class PendingPost {

//发送的事件都是封装到PendingPost中了,然后存到一个pendingPostPool 消息队列中

private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();

}




3个Poster可以结合register和post方法讲解,即通过builder模式创建EventBus的时候,初始化的3个Poster



EventBus.getDefault()的时候就调用了构造方法初始化了3个Poster



public static EventBus getDefault() {

    if (defaultInstance == null) {

        synchronized (EventBus.class) {

            if (defaultInstance == null) {

                defaultInstance = new EventBus();

            }

        }

    }

    return defaultInstance;

}

public EventBus() {

    this(DEFAULT_BUILDER);

}



EventBus(EventBusBuilder builder) {

    mainThreadPoster = new HandlerPoster(this)

    backgroundPoster = new BackgroundPoster(this);

    asyncPoster = new AsyncPoster(this);

 

}

//POSTING 直接去调用事件

case POSTING:

//先判断是否在主线程,在,就会直接调用

//否则通过mainThreadPoster.enqueue将事件发送给主线程执行方法,里面会有一个队列排队的过程,不会阻塞主线程

case MAIN:

//mainThreadPoster默认不过null, 所以这种情况下会直接将事件发送给一个队列,然后依次取出,发送给主线程执行,这种情况下不会阻塞主线程    

case MAIN_ORDERED:

//内部通过一个线程池将事件发送给子线程执行,当有新的任务到来的时候,会存放到一个任务队列中,等待任务执行完之后,才会执行新任务    

case BACKGROUND:

//内部通过一个线程池将事件发送给子线程执行,当有新的任务到来的时候,直接再开一个新线程

case ASYNC:



POSTING:和发送方保持同一线程,发送在主,接收也在主,发送在子,接收也在子  

MAIN:不管发送方在哪里,始终在Main线程  

ASYNC:不管发送方在哪里,始终开启新线程  

BACKGROUND:如果发送方在主线程,BACKGROUND则会新开一个线程;如果发送方在子线程,BACKGROUND则会在相同的子线程中  

MAIN\_ORDERED:和MAIN一样,但事件会按先后顺序执行。



1、四种模式分别是:POSTING、MAIN、BACKGROUND、ASYNC。如果是想更新UI就使用MAIN模式,如果要进行耗时操作最好是使用ASYNC,因为这个模式能永远保证在不一样的线程中进行操作,而且都是子线程。



(1)POSTING:这种模式就是eventBus默认的模式,我们在使用的时候不需要再订阅者的方法的注解后面加任何东西(选择模式),但是这种只能在同一个线程中接收,也就是说,如果是在主线程中发布消息就只能在主线程中接收消息,如果是在子线程中,那么也只能在相同的子线程中去接收消息。



### 写在最后

对程序员来说,很多技术的学习都是“防御性”的。也就是说,我们是在为未来学习。我们学习新技术的目的,或是为了在新项目中应用,或仅仅是为了将来的面试。但不管怎样,一定不能“止步不前”,不能荒废掉。


![](https://img-blog.csdnimg.cn/img_convert/9268d85aa420cd778d04876811843277.webp?x-oss-process=image/format,png)

![![](https://img-blog.csdnimg.cn/img_convert/5521a5abad8ff4eccce978b48f40666a.webp?x-oss-process=image/format,png)
![[]
](https://upload-images.jianshu.io/upload_images/22459598-3e1bbd9b84cc0ef9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![](https://img-blog.csdnimg.cn/img_convert/ed19e48608df7223faa946e6bc803c55.webp?x-oss-process=image/format,png)
![](https://img-blog.csdnimg.cn/img_convert/867c89990d991b8b2fba04c0ca682c57.webp?x-oss-process=image/format,png)

>文章以下内容会给出阿里与美团的面试题(答案+解析)、面试题库、Java核心知识点梳理等
>



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**



### 写在最后

对程序员来说,很多技术的学习都是“防御性”的。也就是说,我们是在为未来学习。我们学习新技术的目的,或是为了在新项目中应用,或仅仅是为了将来的面试。但不管怎样,一定不能“止步不前”,不能荒废掉。


[外链图片转存中...(img-c4mDp4Os-1715665771229)]

[外链图片转存中...(img-lam5Fkg1-1715665771229)]
![[]
](https://upload-images.jianshu.io/upload_images/22459598-3e1bbd9b84cc0ef9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

[外链图片转存中...(img-xNAP88KH-1715665771230)]
[外链图片转存中...(img-BDEQFAWU-1715665771230)]

>文章以下内容会给出阿里与美团的面试题(答案+解析)、面试题库、Java核心知识点梳理等
>



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 10
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值