2024年Android最新面试官问我:Android EventBus的源码,看我如何用漫画装逼!,2024年最新android直播面试题

尾声

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。

进阶学习视频

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

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

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

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

Intent intent = new Intent(MainActivity.this, SecondActivity.class);

startActivity(intent);

}

});

}

@Subscribe(threadMode = ThreadMode.MAIN)

public void onMyEvent(MyEvent event) {

message.setText(event.getMessage());

}

/**

  • 初始化数据

*/

private void initData() {

EventBus.getDefault().register(this);

}

@Override

protected void onDestroy() {

super.onDestroy();

EventBus.getDefault().unregister(this);

}

}

通过EventBus.getDefault().register(this);方法注册订阅者。

3)发送消息

public class SecondActivity extends Activity {

private TextView message;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_second);

initView();

}

/**

  • 初始化布局组件

*/

private void initView() {

message = findViewById(R.id.message);

message.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

EventBus.getDefault().post(new MyEvent(“1”,“这是从SecondActivity发送过来的消息”));

Toast.makeText(SecondActivity.this, “消息发送成功”, Toast.LENGTH_SHORT).show();

}

});

}

}

通过EventBus.getDefault().post(new MyEvent(“1”,“这是从SecondActivity发送过来的消息”));方法发送消息

源码分析


EventBus的使用先注册订阅者,并实现方法,然后再发送post消息,所以我们分析源码也按照这个顺序来。

1)实例化EventBus

EventBus.getDefault().register(this);

该方法首先获取EventBus实例,然后再注册,源码如下所示:

/** Convenience singleton for apps using a process-wide EventBus instance. */

public static EventBus getDefault() {

if (defaultInstance == null) {

synchronized (EventBus.class) {

if (defaultInstance == null) {

defaultInstance = new EventBus();

}

}

}

return defaultInstance;

}

可以看到,实例化EventBus是个双重锁的单例模式。

接下来看EventBus的构造函数,源码如下:

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;

}

可以看到,在EventBus的构造函数中,初始化了一大堆变量,这边主要关注前面两个。

subscriptionsByEventType = new HashMap<>();:key:事件类型(如:MyEvent ),value:新的订阅对象的集合,包括订阅者和订阅者包含的方法。具体赋值逻辑在后面会讲,这边先了解即可。

typesBySubscriber = new HashMap<>();:key:事件的订阅者(MainActivity ),value:事件类型的集合。订阅者跟事件类型是一对多的关系,所以一个界面可以支持多个事件类型。

2)注册

/**

  • Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they

  • are no longer interested in receiving events.

  • Subscribers have event handling methods that must be annotated by {@link Subscribe}.

  • The {@link Subscribe} annotation also allows configuration like {@link

  • ThreadMode} and priority.

*/

public void register(Object subscriber) {

//1.拿到订阅对象的类型;

Class<?> subscriberClass = subscriber.getClass();

//2.通过findSubscriberMethods方法获取该订阅者中的所有订阅方法,因为可能包含多个订阅方法,所以返回集合。

List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);

synchronized (this) {

for (SubscriberMethod subscriberMethod : subscriberMethods) {

//3.通过subscribe方法为每个订阅方法进行订阅。

subscribe(subscriber, subscriberMethod);

}

}

}

如何获取该订阅者中的所有订阅方法,这边主要看第二件事情的处理过程,及findSubscriberMethods方法的源码

List findSubscriberMethods(Class<?> subscriberClass) {

//先拿订阅对象在本地缓存中查找,提高性能。

List subscriberMethods = METHOD_CACHE.get(subscriberClass);

if (subscriberMethods != null) {

return subscriberMethods;

}

//默认情况下ignoreGeneratedIndex值是false的

if (ignoreGeneratedIndex) {

//使用反射方法拿到订阅者中的订阅方法

subscriberMethods = findUsingReflection(subscriberClass);

} else {

//使用编译期间生成的SubscriberInfo

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;

}

}

可以看到上面方法做了三件事:

1.先拿订阅对象在本地缓存中查找订阅方法

2.如果本地获取不到,则根据ignoreGeneratedIndex的值决定获取订阅方法的方式

3.本地保存订阅方法。

可以看到获取订阅的关键方法为:findUsingInfo(),那么赶紧看下他的源码,如下:

private List findUsingInfo(Class<?> subscriberClass) {

FindState findState = prepareFindState();

findState.initForSubscriber(subscriberClass);

while (findState.clazz != null) {

// 获取订阅者信息,没有配置MyEventBusIndex返回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 {

// 通过反射来查找订阅方法,所以为了提高性能,我们还是要用索引的形式使用EventBus

findUsingReflectionInSingleClass(findState);

}

findState.moveToSuperclass();

}

return getMethodsAndRelease(findState);

}

获取到订阅方法后,我们看真正的注册方法subscribe(subscriber, subscriberMethod);

// Must be called in synchronized block

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {

//获取到事件类型(如:MyEvent )

Class<?> eventType = subscriberMethod.eventType;

//把订阅者和订阅者方法重新封装成新的对象

Subscription newSubscription = new Subscription(subscriber, subscriberMethod);

//事件类型为key,新的订阅者对象列表为value,存储进subscriptionsByEventType

//该集合很重要,当post消息的时候,就是从该集合中查找订阅者对象列表

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

}

}

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,存储进typesBySubscriber

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

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

}

}

}

可以看到上面方法做了两件事:

1.根据订阅方法的优先级,添加到订阅列表,事件类型为key,订阅列表为value,存储进subscriptionsByEventType

2.订阅者为key,事件类型列表为value,存储进typesBySubscriber

3)发送消息

/** Posts the given event to the event bus. */

public void post(Object event) {

PostingThreadState postingState = currentPostingThreadState.get();

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

}

最后

针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

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

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

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

celed) {

throw new EventBusException(“Internal error. Abort state was not reset”);

}

最后

针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

[外链图片转存中…(img-MGZUct6f-1715682677574)]

[外链图片转存中…(img-SojJZVal-1715682677574)]

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

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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值