EventBus 3.1.1基础使用和原理浅析

EventBus 3.1.1基础使用和原理浅析

1、简介

EventBus 是一个 Android 事件发布/订阅框架,通过解耦发布者和订阅者简化 Android 事件传递。
本文基于EventBus 3.1.1进行事件发布/订阅的使用和原理解析。

2、基础使用

①、添加依赖

compile 'org.greenrobot:eventbus:3.1.1'     

②、注册
以在Activity中为例:

@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus eb = EventBus.getDefault();
        if (!eb.isRegistered(this)) {
            eb.register(this);
        }
    }

③、反注册
如果注册了那么一定要反注册,否则会导致内存泄漏
以在Activity中为例:

@Override
    protected void onDestroy() {
        EventBus eb = EventBus.getDefault();
        if (eb.isRegistered(this)) {
            eb.unregister(this);
        }
        super.onDestroy();
    }

④、添加接收方法

	//@Subscribe 注入事件接收方法,如果一个activity或者fragment已经注册了,那么必须拥有至少一个事件接收方法
	//threadMode = ThreadMode.MAIN 该方法的逻辑在主线程中执行,可更改为BackGround使逻辑在后台线程执行
	//onEvent 方法名,可随意取,不同的activity中的方法名可以重复
	//(Object Event) 唯一标示,假如此处写(User user),那么该方法只能接收User类型的消息
	@Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(Object event) {
        //TODO 接收到消息后的逻辑
    }

⑤、发送消息

	//这里的event的引用类型,就是onEvent接收方法里Object要明确指定的类
	EventBus.getDefault().post(event);

3、原理浅析

①、register方法

 public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

通过传入类获取class对象和subscriberMethods,这里着重看一下findSubscriberMethodsf()方法

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        if (ignoreGeneratedIndex) {
            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;
        }
    }

这个方法中通过class对象获取了该class里所有的事件接收方法,并返回一个List,再来看一下SubscriberMethod这个类

public class SubscriberMethod {
    final Method method;//Method对象,用于反射调用
    final ThreadMode threadMode;//事件接收方法内逻辑执行在何种线程
    final Class<?> eventType;//事件接收方法接受的形参引用类型
    final int priority;//优先级
}

在register方法中通过

synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }

将所有的SubscriberMethod封装为Subscription对象存入subscriptionsByEventType这个Map集合中
②、post方法

/** Posts the given event to the event bus. */
    public void post(Object event) {
        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()) {
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

可以看到该方法最终调用了这个方法来执行post

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

该方法通过调用来执行post

postSingleEventForEventType(event, postingState, eventClass);

下面看一看这个方法做了什么事情

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;
                try {
                    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;
    }

可以看到,这个方法通过eventClass从subscriptionsByEventType中获取了CopyOnWriteArrayList subscriptions集合,并通过循环的方式逐一调用postToSubscription方法来进行post,那么在看看postToSubscription方法

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

这个方法中,发现了invokeSubscriber方法,那么继续往下看

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

这里就很明显的可以看见,该方法使用Method对象利用反射直接调用订阅方法,实现了事件订阅。
③、性能问题
从以上原理浅析可以得出一个结论
1> 每一次register,EventBus就会把同一个EventType的订阅方法Method对象存入同一个List集合并放入Map中进行管理。
2> 每次post,都会通过EventType从Map中取出所有List,然后循环该List逐一调用反射方法进行消息发送。
3> 因为反射是比较耗费资源的,所以在定义事件的时候尽量避免无用的调用,也就是说尽量细化event。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值