Android 开源项目EventBus详解

使用

//MainActivity
public class MainActivity extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        EventBus.getDefault().register(this); //注册MainActivity到eventbus
    }
    @OnClick(R.id.but)
    void onClick() {
        startActivityForResult(new Intent(this, AnoActivity.class), TEST_REUQUEST_CODE);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        formatCurrentTime("onActivityResult");
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == TEST_REUQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK) {
                if (data == null) {
                    return;
                }
                QDLog.d("onActivityResult text:" + data.getStringExtra("textview"));
            }
        }
    }

    public void onEventMainThread(Object object) {
        QDLog.d("onEventMainThread object:" + object.toString());
    }

    public void onEventMainThread(String text) {
        QDLog.d("onEventMainThread text:" + text);
    }

    public void onEvent(String text) {
        QDLog.d("onEvent text:" + text);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this); //别忘记去注册,否则会引起activity释放不了,最后导致OOM
    }
}

    //MainActivity跳转到AnoActivity
    @OnClick(R.id.but)
    void OnClick() {
        EventBus.getDefault().post("event buts for test");
        Intent intent = new Intent();
        intent.putExtra("textview", "onActivityResult for test");
        setResult(Activity.RESULT_OK, intent); //setResult必须放在finish之前,否则resultCode设置无效的
        finish();
    }

以上使用了两种通信方式,1. intent 2. eventbus
不使用eventbus,我们一般使用intent作为activity之间互相通信

最后结果:
12-27 04:55:12.206 19141-19141/demo.lbb.mytest D/LiaBin: onEvent text:event buts for test
12-27 04:55:12.206 19141-19141/demo.lbb.mytest D/LiaBin: onEventMainThread text:event buts for test
12-27 04:55:12.206 19141-19141/demo.lbb.mytest D/LiaBin: onEventMainThread object:event buts for test
12-27 04:55:12.217 19141-19141/demo.lbb.mytest D/LiaBin: onActivityResult text:onActivityResult for test

注意:虽然post的是String类型,但是String是Object的间接之类,同时库中eventInheritance默认为true,所以onEventMainThread(Object object)也可执行到,见以下分析

此时注意到

  1. eventbus方式只要调用post方法,那么MainActivity的onEvent..方法就能执行到;
  2. intent方式只有把anoactivity销毁finish了才会回调onActivityResult方法。

所以有这么个需求,anoactivity点击同时停留在本界面,然后mainactivity立刻执行某项任务,那么eventbus无疑是很合适的

源码分析

先上原理图:

eventbus实际上实现的就是观察者模式的功能,只是eventbus内部通过反射来实现的而已

register方法

    private synchronized void register(Object subscriber, boolean sticky, int priority) {
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod, sticky, priority);
        }
    }

List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());通过反射的原理,把当前类和父类的所有onEvent..的方法添加到list,同时返回该list,此时也说明,比如MainActivity继承了BaseActivity,那么onEventMainThread(String text)只有一个地方会生效,另一个会覆盖掉。这里有个优化

            String name = clazz.getName();
            if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
                // Skip system classes, this just degrades performance
                break;
            }

如果是系统包中的类,就中断while了

SubscriberMethod构造如下:

    final Method method; //.MainActivity.onEventMainThread(java.lang.String)
    final ThreadMode threadMode; //MainThread
    final Class<?> eventType; //class java.lang.String

public enum ThreadMode {
    PostThread,MainThread,BackgroundThread,Async //四种模式
}

Subscription构造如下:

    final Object subscriber;
    final SubscriberMethod subscriberMethod;
    final int priority;

subscribe方法源码就不贴了,主要就是对subscriptionsByEventTypetypesBySubscriber全局变量进行赋值

    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; //订阅方法作为key,所有的订阅对象作为value
    此时说明了每种类型,都有几个订阅对象订阅了
    private final Map<Object, List<Class<?>>> typesBySubscriber; //订阅对象作为key,订阅对象中所有的订阅方法作为value
    此时说明订阅对象声明了几个订阅方法
    //MainActivity中有以下三方方法
    public void onEventMainThread(Object object);
    public void onEventMainThread(String text);
    public void onEvent(String text);

所以最后的结果为:
subscriptionsByEventType size为2,第一个key为Object,value长度为1,第二个key是String,CopyOnWriteArrayList>长度是2
typesBySubscriber size为1,key为当前订阅对象,List

post方法

post方法中使用到了currentPostingThreadState来根据线程的状态分别执行

    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };

ThreadLocal是不是很熟悉,ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量
handler机制中就看到了该类的使用,很方便。

post然后调用postSingleEvent方法

    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) { //默认为true
        //此时event实际类型为String,那么最后eventTypes长度为5,里面保存String以及String所有的父类以及实现的接口:
        //String/Serializable/Comparable/CharSequence/Object
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) { //此时会循环5次
                Class<?> clazz = eventTypes.get(h);
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        ....
    }
    private List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
        synchronized (eventTypesCache) {
            List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
            if (eventTypes == null) {
                eventTypes = new ArrayList<Class<?>>();
                Class<?> clazz = eventClass;
                while (clazz != null) {
                    eventTypes.add(clazz);
                    addInterfaces(eventTypes, clazz.getInterfaces());//拿到该class实现的所有接口
                    clazz = clazz.getSuperclass();
                }
                eventTypesCache.put(eventClass, eventTypes);
            }
            return eventTypes;
        }
    }

private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<Class<?>, List<Class<?>>>();//String,Object等发布类型为key,List

   private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass); //subscriptionsByEventType取出订阅者
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;
                try {
                    postToSubscription(subscription, event, postingState.isMainThread); //掉用postToSubscription方法
                    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 PostThread:
                invokeSubscriber(subscription, event); //在当前线程中调用订阅方法,所以最好不要使用该模式,而是使用以下三种模式
                break;
            case MainThread:
                if (isMainThread) { //如果当前线程是main线程,直接调用订阅方法
                    invokeSubscriber(subscription, event);
                } else { //否则通过mainThreadPoster,内部通过handler,发送到main线程中执行订阅方法
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case BackgroundThread:
                if (isMainThread) { //如果当前线程是main线程,缓存线程池中新建一个线程执行订阅方法
                    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);
        }
    }
    subscription.subscriberMethod.method.invoke(subscription.subscriber, event); //最后都是执行到了这里,反射方法执行
    private final HandlerPoster mainThreadPoster; //继承自handler,内部持有main线程的loop
    private final BackgroundPoster backgroundPoster; //继承自runnable,执行放在线程池中运行
    private final AsyncPoster asyncPoster; //继承自runnable,执行放在线程池中运行
    private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool(); //默认使用缓存线程池来管理

总结一下:
每注册一个对象和方法,就放入map,之后post(Object)就去这个Map中查找匹配的类方法调用
可以看到此时不仅可以接收activity,service等组件的注册,其实可以接收任何类的注册

缺点

1. 这里使用到了build设计模式什么鬼,设计的有点差劲,,
EventBusBuilder完全就是个摆设,为了把eventInheritance置为false,只有修改库源码了,没有提供接口供修改
eventInheritance设为false,极大的提升了性能

任何项目引入开源项目一定要对开源项目后,进行修改,不能只照搬。

2. 自定义queue导致性能差
BackgroundPoster的run方法

    private final PendingPostQueue queue;
    @Override
    public void run() {
        try {
            try {
                while (true) {
                    PendingPost pendingPost = queue.poll(1000);
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
                Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

PendingPostQueue是一个自定义的队列,方法内部使用synchronized关键子来防止多线程造成的同步问题,麻烦同时效率低下,为何不直接使用BlockingQueue队列,参考Volley实现,BlockingQueue是java推荐的实现方式

3. 默认线程池的选择CachedThreadPool
默认线程池使用的是CachedThreadPool,虽然实时性好,但是频繁的创建线程,开销大
CachedThreadPool特性:excute了一个任务,就创建一个线程,不需要等待

我觉得使用newFixedThreadPool可能会更好些,虽然实时性可能不大好,会等待

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值