EventBus原理源码分析和使用

本文详细分析了EventBus的设计原理,通过源码解读揭示了其发布/订阅机制的实现细节。同时,介绍了如何在实际项目中有效使用EventBus,为Android开发中的组件间通信提供便利。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前段时间被别人问到关于EventBus的原理,但我确实使用过,用起来也方便简单,一个注册,一个Post就能通知到所有的订阅者Subcriber,其实明明是知道一点点原理的,但是当时就是支支吾吾没有说,太low了,回来大概看了一眼EventBus的源码及实现原谅,现在想把看原代码的一些心得进行记录。OK,我们从Github上面了解一下官方如何介绍这个EventBus吧。
翻译:EventBus是一个事件发布/订阅总线,有效适用于Android系统平台。 
EventBus... 
.组件之间的通信更加简单 
。针对在事件的发送者和订阅者之间进行解耦 
。非常好的运用在Activitys、Fragments和后台线程 
。避开了联系紧密易出错的依赖关系和容易出错生命周期 
.使你的代码更加简洁 
.快 
.瘦(小于50K的jar包) 
.有100,00,000+的app使用了EventBus
简单翻译就是这样一个意思,翻译不好请多担待,但是尽管翻译很差,但是大体的原理描述和工作是体现出来了。我是直接从Github上下载的最新的源代码进行研究的,在这里我想提出一个注意的地方,之前的旧一点的版本3.0之前的版本,订阅者的事件通知的方法都是通过开发者遵守命名约定,这样没有安全性,容易出错,很不方便开发,但是后来3.0开始使用注解的方式对事件的方法的声明。如下是之前的版本使用的命名约定的方式。
1、onEvent
2、onEventMainThread
3、onEventBackgroundThread
4、onEventAsync
现在最新版本订阅者的事件方法名称可以随意声明,只要在方法的上简单的加上一些相关的注解就可以了,而且注解是必须加上的,否则会抛出Runtime异常。OK,看看我们现在的做法:
</pre><pre code_snippet_id="1679566" snippet_file_name="blog_20160511_1_5619972" name="code" class="java">import org.greenrobot.eventbus.EventBus;
public class MainActivity extends Activity implements OnClickListener {
    private Button mButton;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main_layout);
            final Intent  intent= new Intent(this,EventBusTestService.class);
            startService(intent);
            EventBus.getDefault().register(this);
            mButton = (Button) findViewById(R.id.button1);
            mButton.setOnClickListener(this);
        }

        @Subscribe(threadMode=ThreadMode.ASYNC)
        public void onEventReceive(EventBusMsg msg){
            Log.d("ZHG-EventBusTest","MainActivity.onEventReceive , msg = "+msg.msg +" , MainThreadID = "+this.getMainLooper().getThread().getId()+" , currentTreadID = "+Thread.currentThread().getId());
        }

        @Override
        public void onClick(View view) {
                switch (view.getId() ) {
                case R.id.button1:
             EventBus.getDefault().post(new EventBusMsg("Test Message!!!!"));
                    break;
                default:
                    break;
                }
        }

        @Override
        protected void onDestroy() {
            super.onDestroy();
            EventBus.getDefault().unregister(this);
        }
}
package com.example.eventbustest;
import org.greenrobot.eventbus.EventBus;
public class EventBusTestService extends Service {
    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        EventBus.getDefault().register(this);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    @Subscribe(threadMode=ThreadMode.BACKGROUND)
    public void onEventBusMsgReceive(EventBusMsg msg){
        Log.d("ZHG-EventBusTest","EventBusTestService.onEventBusMsgReceive , msg = "+msg.msg +" , MainThreadID = "+this.getMainLooper().getThread().getId()+" , currentTreadID = "+Thread.currentThread().getId());
    }
}
 
从上面的示例代码就能看出,最新的版本再也不用那么麻烦的去记住什么约定的方法怎么写,不用再去背了,现在只要自己命名成自己喜欢的方法名,然后简单的加上注解就行,而且还可以设置线程模式,比如是是否在主线程、子线程、是否异步等。
OK,上面是针对使用上的一些变化进行一个温馨提示,接下来直接奔入主题,看源代码把。
1. EventBus.getDefault();开始
入口EventBus.getDefault();开始,这里我还是很喜欢这样的静态单例对象获取方法名,我本人也很喜欢使用单例的时候,取名getDefault()。
/** 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;
    }

很简单,就是一个单例设计代码,看看构造方法。
 /**
     * 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) {
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        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);
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        eventInheritance = builder.eventInheritance;
        executorService = builder.executorService;
    }
构造方法中创建了几个容器,用来装各种订阅者信息的,很关键的几个成员我们需要注意,mainThreadPoster 、backgroundPoster 、asyncPoster ,这个几个是后来post消息的时候,用的到的,就是利用他们将消息在不同的线程发送出去,达到在不同线程中执行的效果。
mainThreadPoster:很显然是一个自定义扩展后的Handler,在构造的时候传入的是主线的Looper,所以它是一个主线程的对应的Handler。
这里之间先看看这个Handler的代码吧:
 * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
package org.greenrobot.eventbus;

import android.os.Handler;

final class HandlerPoster extends Handler {

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

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

    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;
        }
    }
} 
没错,就是传入一个MainThread的Looper,创建了一个主线程的Handler,毋庸置疑,通过他发送的事件消息,都是在主线中执行的。

backgroundPoster : 那这个是什么呢,我们来看看代码。
 
 * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
package org.greenrobot.eventbus;

import android.util.Log;

/**
 * Posts events in background.
 * 
 * @author Markus
 */
final class BackgroundPoster implements Runnable {

    
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值