欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

简读Eventbus3.0

程序员文章站 2022-03-08 10:03:14
...

简单了解一下eventbus的工作情况,学学大神的思想,那么在此篇文章之前呢,建议大家先要了解清楚何为注解和反射,如果没了解,可以先看看前一篇文章,有具体的介绍  Android 注解 (Annotation)

使用过eventbus的都知道,eventbus是一个Android事件发布/订阅轻量级框架, 它可以完美的在任何地方完成通信任务,那么不废话啦,按照 咱们在Android中的使用过程为思路展开一个了解吧

一、我们是在需要接受事件的地方(例如activity、fragment) 注册 eventbus事件

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(...);
        //注册eventbus事件
        EventBus.getDefault().register(this);
     
    }

好啦,如上代码,我们在activity的oncreate生命周期方法中注册了eventbus事件,那么来看一下 getDefault()、register()方法到底干了点什么

//第一部分,获取单例(懒汉式,"懒得创建自己")
public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }


//第二部分,注册给定的订阅服务器以接收事件。订阅者必须调用{unregister(Object)取消注册(对象)}
public void register(Object subscriber) {
        //1.首先通过反射获取到当前类
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//2
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);//3
            }
        }
    }

      第一部分 EventBus.getDefault() 是一个懒汉式单例。                                                                              

      第二部分是注册,1.首先通过当前object.getclass()反射方法获取到当前 class对象;    2.然后通过 findSubscriberMethods 方法获取到一个当前class对象的所有方法,并放在一个list集合中,List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); 该行代码中就是就是维护了 一个 ConcurrentHashMap 对象 ; 3.接下来就是一个 synchronized 同步块,把该类和该类的多个方法进行配对订阅

 

二、发送提交和订阅消费

提交事件到总线:  EventBus.getDefault().post(object);

//将给定事件提交到事件总线
public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get(); //1
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {//2
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            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);//3
                }
            } finally { //最终把状态都还原了
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

//-------------------current Posting Thread State --------------------------

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



//------------------Posting Thread State------------------------

/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<Object>(); //消息集合
        boolean isPosting; //是否有发送
        boolean isMainThread; //是否是主线程
        Subscription subscription; //订阅关系
        Object event; //具体发送的事件体
        boolean canceled; //是否取消了
    }

 1. PostingThreadState postingState = currentPostingThreadState.get() 该方法其实就是ThreadLocal对象(线程副本,为线程本身存储变量等信息),而PostingThreadState就是线程副本内所存储JavaBean对象 (在此可以看出,该bean对象并没有get set封装),从bean对象中获取到消息集合,并把当前post所要提交的消息保存在该集合中;

 2. 使用 isposting 来判断是否发送过信息,然后进入下一步判断当前发送post方法执行的线程是否是主线程,设置发送状态,判断消息是否有效,while遍历

3. while在集合非空状态下,会不断遍历 postSingleEvent 方法,不断从集合中获取消息体和副本中数据进行处理,那么在往下查看有  postToSubscription(subscription, event, postingState.isMainThread) 这样的方法,它主要就是获取咱们标签中的value,根据不同的value 在不同的线程做不同的操作

//常用的四个标签
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING://当前线程执行
                invokeSubscriber(subscription, event);
                break;
            case MAIN: //事件的消费会在UI线程。因此,不宜进行耗时操作,以免引起ANR
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case BACKGROUND://背景线程,如果事件在UI线程产生,那么事件的消费会在单独的子线程中进行。否则,在同一个线程中消费。
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC://异步执行,不管是否在UI线程产生事件,都会在单独的子线程中消费事件
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }


//---------------------反射中的 方法执行---------------------------

void invokeSubscriber(Subscription subscription, Object event) {
        try {
            //通过反射获取到要执行的方法 subscription.subscriber,该方法的参数就是 通过 post要提交的消息
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }

三、注销

EventBus.getDefault().unregister(this);

//每个待消费事件的class都会对应一个list集合
private final Map<Object, List<Class<?>>> typesBySubscriber;
//取消注册
public synchronized void unregister(Object subscriber) {
        //获取该activity或fragment对应的注解类
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            // 遍历所有的订阅方法 ,并取消
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            typesBySubscriber.remove(subscriber);
        } else {
            Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }
在使用的时候只是简单导入eventbus jar,我们调用的时候只要简单的注册和配置注解标签即可,极大提供了开发效率,这就是提供框架的好处;另外重要的一点,就是学习文中的“注册”与“注销”的精神,程序做到了有始有终,在开辟了内存,在内存中完成业务,然后在view组件结束生命周期的时候把所占的内存、操作都结束了       ;初次解读,有问题的地方要指出,互相提高吧

 

 

相关标签: 源码