• Android 常用开源框架源码解析 系列 (八)Eventbus 事件发布订阅框架


    EventBus
     
    一、前言
    (一)、作用 
    1、Android 事件发布 / 订阅框架
    2、事件传递既可以用于Android 四大组件间的通信
    3、用户异步线程和主线程间通信的时候进行联系的工具
     
    (二)、意义
    通过框架解耦事件的 发布者 和订阅者 ,进而简化Android 事件传递
     
    (三)、优点
    代码简洁,使用简单,并将事件发布和订阅充分解耦
     
    (四)、传统的事件传递方法
            a、handler
            b、BroadcastReceiver
            c、接口回调
    传统事件传递的缺陷:
        代码量臃肿、繁琐、复杂
     
    传统事件传递之handler
     
    handler 机制工作原理 
     
    ps:Android 中的主线程 :ActivityThread 类——Ui线程
    通过这个类创建的Looper 和 Handler 就可以进行消息的传递了
     
    思考1:子线程是否可以创建handler对象?
    答: 子线程直接创建handler对象会报 缺少Looper对象的错误。进行三个步骤创建handler :
       1、调用Looper的prepare()方法创建当前线程的Looper
        2、之后创建当前线程的Handler()
        3、在创建完Handler()后要通过Looper.loop()开启Looper消息队列的循环
     
    解析:在Android异步消息处理机制中,handler就是用来处理消息的,并进行消息的发送,和处理在handleMessage。
    发出、经过处理的消息最后都会回到handler这个方法中来执行。
    Looper 每个线程中MessageQueue的管家,负责消息队列的运作。Looper内部死循环不断的从MessageQueue中获取消息,
    有消息就取出并返回给handleMessage去进行处理。所以也就是说单单仅有一个handler是无法进行消息的处理工作的,因为没有Looper 无法获取MessageQueue 中的消息。
        也就是说需要handler发送消息后通过Looper接收消息,放到MessageQueue中进行轮询操作。最后looper会将Message 返回给handler,调用handleMessage 方法进行异步消息的处理操作。
     
    思考2:handler 在Activity中进行消息的传递有几种形式?
     
    实例代码一 形式:
    /**
    * 利用handler,在Ui 主线程中发送消息,在work子线程执行耗时操作
    */
    public class HandlerSendMessageActivity extends Activity {
        public Button btn1;
        Handler handler;//主线程handler
        public TextView textview;
     
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
            super.onCreate(savedInstanceState, persistentState);
            setContentView(R.layout.butterknife_layout);
            textview = findViewById(R.id.textview_1);
            btn1 = findViewById(R.id.button_1);
            btn1.setText("Ui->Work");
            btn1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //主线程发送消息给子线程去处理需要耗时的操作
                    Message msg = handler.obtainMessage();
                    msg.arg1 = 1;
                    msg.obj = "obj 消息";
                    handler.sendMessage(msg);
                    System.out.println(Thread.currentThread().getName());
                }
            });
            new MyThread().start();
        }
        class MyThread extends Thread {
            @Override
            public void run() {
                //子线程创建handler之前一定要首先创建looper 通过Looper.prepare();
                Looper.prepare();
                handler = new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        System.out.println(Thread.currentThread().getName());
                        super.handleMessage(msg);
                    }
                };
                Looper.loop();
                super.run();
            }
        }
    }
    实例代码二 形式:
    /**
    * 利用handler,在子线程发送消息,然后在主线程中获取并执行
    */
    public class HandlerGetMessageActivity extends Activity {
        Button btn1;
        //1、主线程定义handler 并重现handleMessage()
       Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                System.out.println(Thread.currentThread().getName());
                System.out.println("消息-->" + msg.arg1 + "-" + msg.obj);
                super.handleMessage(msg);
            }
        };
     
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
            super.onCreate(savedInstanceState, persistentState);
            setContentView(R.layout.butterknife_layout);
            btn1 = findViewById(R.id.button_1);
            btn1.setText("Work-->Ui");
            btn1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //2、开启一个子线程在run()方法中发送消息给主线程处理
                    Thread thread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            Message msg = handler.obtainMessage();
                            msg.arg1 = 1;
                            msg.obj = "obj 消息";
                            handler.sendMessage(msg);
                            System.out.println(Thread.currentThread().getName());
                        }
                    });
                    thread.start();
                }
            });
        }
    }
     
    二、EventBus框架基本用法
     
       (一)eventbus 流程图
     
                        event                               ———event————Subscriber
    Publisher ——————>Event Bus — | 
      (发布器)      post()                              ———event————Subscriber
     
    流程:发布器 通过post()方法 把event 发布到 event bus 总线当中 ,eventbus总线中根据 event 事件类型 匹配给相应的订阅者 
     ps:注意只有注册了事件才能收到event 发送的请求;同时反注册可以清理需要的eventbus请求
     
    (二)eventbus 使用方法
    1、导入:
       implementation 'org.greenrobot:eventbus:3.0.0'
     
    2、定义自定义事件event类型
    public class MyBusEvent{
        public final String message;
        public MyBusEvent(String message) {
            this.message = message;
        }
     
    }
    3、创建订阅者-通过注解
        //订阅者一定要带上@Subscribe注解,eventbus之后的订阅者方法名可以随意
    @Subscribe(定义这个方法完成的线程级别),不用考虑线程问题抛出的异常
    @Subscribe(threadMode = ThreadMode.MAIN) //表示onMessageEvent()在主线程中完成
        public void onMessageEvent(MyBusEvent event) {
            System.out.println();
        }
    }
    4、注册与反注册事件
    @Override
    protected void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }
    @Override
    protected void onStop() {
        super.onStop();
        EventBus.getDefault().unregister(this);
    }
    ps:注册与反注册 如果在Activity 或是fragment 这类组件,尽量与它的生命周期绑定在一起
     
    5、发送事件 -无位置限制-主/子线程均可以发送事件
    btn1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //主线程发送消息给子线程去处理需要耗时的操作
            Message msg = handler.obtainMessage();
            msg.arg1 = 1;
            msg.obj = "obj 消息";
            handler.sendMessage(msg);
        //将自定义的事件类型,作为参数传递给post()函数
            EventBus.getDefault().post(new MyBusEvent("test fot eventbus"));
        }
    });
    ps:所有注册、订阅这个事件的订阅者都能够匹配接收的这个事件xxx
     
     
    三、EventBus框架的对象构建 和线程调度
     EventBus 的实例化均带有EventBus.getDefault() 方法,所以以此为入口:
     
    简单来说:EventBus就是一个单例模式创建并用构建者模式Build内部类构建的对象
     
    EventBus.getDefault():双检查机制的单例模式
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }
     
    思考:单例模式构造函数一般都是private修饰的,但是eventBus的构造模式是public 修饰的,这个原因是?
    publicEventBus() {
        this(DEFAULT_BUILDER);
    }
    private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
     
    解析:EventBus在代码中并不是只有一条 总线,还有其他的总线。订阅者可以注册到不同的EventBus上,通过不同的EventBus发送数据。不同的EventBus发送的数据是相互隔离开的,订阅者只会收到注册在该线程上的数据。通过上面DEFAULT_BUILDER 对象的初始化可以发现EventBus构建对象是通过构建者模式 Builde内部类 进行构建的。
     
    EventBus 的对象构建 
        
     
    private final ThreadLocal<PostingThreadState> currentPostingThreadState= new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };
    ps:ThreadLocal是 线程内部的数据存储类 ,通过它可以在指定的线程中存储数据,也只有在指定的线程中可以获取到数据。其他线程无法获取到
     
     
    EventBus(EventBusBuilder builder) {
        subscriptionsByEventType = new HashMap<>(); 
        //以event 为key,以subscribe为value值
        ps:可以通过subscriptionsByEventType这个HashMap找到对应的订阅者
     
        typesBySubscriber = new HashMap<>(); 
        //以subscribe为key,以event为value
        ps:当进行注册和反注册事件的时候都会在这个typesBySubscriber HashMap中操作
     
        stickyEvents = new ConcurrentHashMap<>();
        //粘性事件,当event发送出去后再注册粘性事件的话,这个粘性事件也能收到之前发送的event事件
       ps:ConcurrentHashMap是一个并发的HashMap
     
    思考 :什么是post? 答: 负责线程间调度 
        三个比较重要的成员变量的初始化 mainThreadPoster、backgroundPoster、asyncPoster
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        backgroundPoster = new BackgroundPoster(this);
        asyncPoster = new AsyncPoster(this);
     
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; //eventbus生成的索引
     
        //对已经设定好注解的@Subscribe的Method方法的找寻器    
        //通过这个方法找寻设定好注解的方法
    subscriberMethodFinder= new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
     
     
        logSubscriberExceptions = builder.logSubscriberExceptions; //发生异常是否进行异常信息的打印
        logNoSubscriberMessages = builder.logNoSubscriberMessages;//没有订阅者订阅该事件的时候是否打印日志
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;//当调用事件处理函数时若发生异常是否需要发送这个事件
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;//当没有事件处理的时候是否对事件处理发送sendNoSubscriberEvent
        throwSubscriberException = builder.throwSubscriberException;//是否需要抛出异常
        eventInheritance = builder.eventInheritance; //与event有继承关系的是否都需要发送
        executorService = builder.executorService;
    }
     
    下面看一下eventBus 最核心的三个线程间调度的方法:
     
        (1) 、mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
    final class HandlerPoster extends Handler所以可知其实际上就是个handler 具柄
    //存放即将执行的post的队列
    private final PendingPostQueue queue; 
     
    //post这个事件最大的所能在handler当中handleMessage()所存在的最大时间值 max值
    private final int maxMillisInsideHandleMessage;
     
    //标着者handler是否运行起来
    private boolean handlerActive;
     
    在handleMessage()方法的任务,首先开启while一个循环,从队列中不停的获取数据后,调用invokeSubscriber()方法进行事件的分发
    eventBus.invokeSubscriber(pendingPost);
    //然后,每分发完一次事件都会对比下时间,判断这个method的时间timeInMethod 是否大于等于maxMillisInsideHandleMessage这个最大值时间,若小于就跳出循环,来继续下面的操作
    long timeInMethod = SystemClock.uptimeMillis() - started;
    if (timeInMethod >= maxMillisInsideHandleMessage) 
     
    handleMessage() 循环的源码:
    while (true) {
        //从前面定义好的queue队列中通过poll方法拉取需要的PendingPost对象
        pendingPost实际上就是一个维护着可以复用的对象的复用池 
        PendingPost pendingPost = queue.poll();
     
    ps:PendingPost是一个arrayList,内部有两个核心方法:获取pendingPost:obtainPendingPost() 和 
    回收pendingPost:releasePendingPost()
     
        if (pendingPost == null) {
            synchronized (this) {
                // Check again, this time in synchronized
                pendingPost = queue.poll();
                if (pendingPost == null) {
                    handlerActive = false;//设置标志位为false,说明handler还没有运行
                    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;
        }
    }
     
    (2) 、backgroundPoster = new BackgroundPoster(this);
    final class BackgroundPoster implements Runnable
    @Override
    public void run() {
        try {
            try {
               //在while循环中不断的从队列中获取消息,同样通过类似的eventBus.invokeSubscriber 进行事件的分发
            ps:注意这里是有一个限定条件,直到取完池中所以的为止
                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;
        }
    }
    (3) 、asyncPoster = new AsyncPoster(this);
    AsyncPoster implements Runnable ,区别与BackgroundPoster:
        只获取队列中一个PendingPost,然后进行invokeSubscriber()事件的分发
    @Override
    public void run() {
        PendingPost pendingPost = queue.poll();
        if(pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        }
        eventBus.invokeSubscriber(pendingPost);
    }
     
     
    四、EventBus框架的subscribe注解 
    @Documented  //指定为是一个JavaDocument 文档
    @Retention(RetentionPolicy.RUNTIME)  //指定可以在运行时有效
    @Target({ElementType.METHOD}) //指定用来描述方法
    public @interface Subscribe{ 
            //线程模式
             ThreadModethreadMode() default ThreadMode.POSTING;
        boolean sticky() default false; //判断是否为粘性事件
        int priority() default 0;
    }
    ThreadMode 枚举类:
        POSTING 
        / 默认的线程模式;在执行post操作的时候线程会直接调用订阅者的事件方法
         MAIN  
        / 在主线程中执行;当发布线程是在主线程可以直接调用该订阅者的方法;否则需要通过handlePost发送消息
        BACKGROUND--backgroundPost进行调度(所有队列)
        / 后台线程;表示在后台线程中执行相应的方法,如果发布线程不是在主线程中,不可以直接调用订阅者函数,必须启动唯一的后台线程进行处理,后台线程是唯一的,当事件发送post超过一个的时候会被放置在这里依次处理
        ASYNC —asyncPoster 每次只会从队列里获取一个所以不存在卡顿
       / 不论方法线程是在哪个线程都会使用一个空线程进行处理;Async所有的线程都相互独立,不会出现线程卡顿现象
     
    粘性事件
        事件消费者在事件发布之后才注册的也能接收到该事件的特殊类型
     
    Sticky Broadcast 粘性广播-传统
    粘性广播存在的意义:
            在正常情况下,如果发送者发送了某个广播,而接受者在这个广播发送广播之后才注册广播接收者的话,那么广播接收者是无法接受到刚才的广播的。
     
    引入之后:
        当接收者注册完之后,还可以接收到刚才发出的广播
    在广播发射结束后保存刚刚发送的广播
     
    区别于传统:
    Android 的 EventBus会存储所有的Sticky事件,也就是说某个事件不需要的时候就进行手动的移除操作
     
    五、EventBus框架的register订阅者
    每新建一个eventbus总线,它的发布和订阅事件都是相互隔离的
     
    举例:创建一个eventbus对象,在这个对象中通过他发布事件;然后又创建一个eventBus对象,在这个eventbus对象中,订阅者是不会收到前一个eventbus所发生的事件的
     
    public void register(Object subscriber) {
       //通过反射机制 获取到订阅者的class对象
        Class<?> subscriberClass = subscriber.getClass();
        //register的核心方法——findSubscriberMethods
    通过subscriberMethodFinder找寻器的findSubscriberMethods订阅对象class找到订阅方法的集合,返回一个订阅方法的集合
        List<SubscriberMethod> subscriberMethods = 
       //完成注册订阅的第一步:
    subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        //遍历订阅好的方法集合 ,进行每个方法的订阅操作
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }
     
    findSubscriberMethods():
    //SubscriberMethod 类型的 List
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    SubscriberMethod:EventBus 总的包装类
     
    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        //1、从方法缓存池中查找是否已经有了这个方法,如果有的话就把这个集合返回
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
        //索引的判断(默认是false) ,所以会进入findUsingInfo()方法
        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 {
            //将subscriberMethods 存储到METHOD_CAHCE当中
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }
     
    findUsingInfo():
    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        //1、获取到FindState对象 ,找到订阅过的方法和其状态,如果没有就new 新建一个FindState对象
        FindState findState = prepareFindState();
              ...
      ps:FindState(){
        定义:
        //保存所有订阅方法的ArrayList
                final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
        //保存事件类型为key ,订阅类型为value的HashMap
                final Map<Class, Object> anyMethodByEventType = new HashMap<>();
        // 订阅方法为Methodkey,订阅者的class对象为value
                final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
         }   
     
    //找到FindState对象的state状态
    private FindState prepareFindState() {
        //从Find state对象池中查找
        synchronized (FIND_STATE_POOL) {
                //遍历对象池查找需要的 state对象
            for (int i = 0; i < POOL_SIZE; i++) {
                FindState state = FIND_STATE_POOL[i];
                if (state != null) {
                   //已经找到了可用的复用的State,这时候将该位置清空,为了以后可以继续复用它,并返回这个状态给FindState()函数
                    FIND_STATE_POOL[i] = null;
                    return state;
                }
            }
        }
    //当遍历完整个对象池还没有找到需要的state的时候调用new FindState()创建一个新的state
        return new FindState();
    }
       ...
        ...
        findState.initForSubscriber(subscriberClass);
        ...
    //在while 循环结尾 每一次循环之后都会通过moveToSuperclass()进行下一次的循环
        while (findState.clazz != null) {
            //getSubscriberInfo()函数获取到FindState订阅者的信息
            findState.subscriberInfo = getSubscriberInfo(findState);
     
            if (findState.subscriberInfo != null) {
           //首先获得 findState对象当中的订阅方法的集合
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
               //通过for循环进行 订阅方法的遍历
            for (SubscriberMethod subscriberMethod : array) {
                    //订阅方法过滤操作—> 返回true ,订阅好的方法,以及订阅方法的事件类型都是符合它的准则的
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                    //将订阅的方法添加到findState的arrayList中,也就是subscriberMethods
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
                    //如果getSubscriberMethods() 返回为null 空,则进入下面 
    ps:getSubscriberMethods()默认情况下一般都是null 
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }
     
     
    findState.checkAdd():
    boolean checkAdd(Method method, Class<?> eventType) {
        //以eventType事件类型为key,以method为value
       //1、anyMethodByEventType.put()会返回之前的方法
        Object existing = anyMethodByEventType.put(eventType, method);
        if (existing == null) {
            return true;
        } else {
       ps:在eventbus中 有一种特点:
        一个订阅者包括订阅者的所有的父类和子类,不会有多个方法,相同的全部去接收同一个事件;
       
            if (existing instanceof Method) {
                if (!checkAddWithMethodSignature((Method) existing, eventType)) {
                    throw new IllegalStateException();
                }
                anyMethodByEventType.put(eventType, this);
            }
        但有可能子类有可能会订阅该事件,同时它的父类也会订阅该事件的时候,会调用checkAddWithMethodSignature()来根据方法的签名来检查
            return checkAddWithMethodSignature(method, eventType);
        }
    }
    checkAddWithMethodSignature():根据方法的签名来检查过滤
    private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
        methodKeyBuilder.setLength(0);
        methodKeyBuilder.append(method.getName());
        methodKeyBuilder.append('>').append(eventType.getName());
        String methodKey = methodKeyBuilder.toString();
        Class<?> methodClass = method.getDeclaringClass();
        //以方法为key,以订阅好的类的class对象为value;
        //调用put方法()也会和之前一样会返回之前的订阅的class对象,然后根据class对象进行下一步操作
        Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
      //如果这个class对象不存在 ,或者是这个值是method 对象的父类的话就会返回true
        if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
            return true;
        } else {
          //如果不是的话 ,或是class对象是空,就会把methodKey作为key 添加到subscriberClassByMethodKey 这个HashMap中
            ps:这个时候并没有put内容进缓存;因为put的值是methodClassOld是以前的class
        put()方法目的是revery:不要出现一个订阅者有多个相同方法,订阅同一个事件,如果有的话就把以前的这个class放到hashMap中去覆盖
            subscriberClassByMethodKey.put(methodKey, methodClassOld);
            return false;
        }
    }
     
    findUsingReflectionInSingleClass():通过这个方法找到哪些是订阅者订阅好的方法 或是 事件
    private void findUsingReflectionInSingleClass(FindState findState) {
        …
      //1、通过反射的getDeclaredMethods() 获取到订阅者所有的方法
      methods = findState.clazz.getDeclaredMethods();
        …
      //2、对前面获取到的方法进行依次的遍历
      for (Method method : methods) {
         //3、获取到方法的修饰符 ,然后用这个修饰符进行判断
         int modifiers = method.getModifiers();
         //4、判断这个方法是否是public 以及该方法的修饰符是否可以忽略
          if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0){
            //5、getParameterTypes()获取方法的参数
           Class<?>[] parameterTypes = method.getParameterTypes();
               //6、进行方法参数的判断是否等于1
                ps:eventbus中只允许订阅方法后面的订阅事件是1个,所以通过方法参数长度的判断过滤出参数只有1哥的方法
                if (parameterTypes.length == 1) {
                   //7、调用getAnnotation()方法获取Subscribe对象,用来过滤出只被@Subscribe修饰过的方法
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                        …
                    //8、被subscribeAnnotation过滤好的方法的threadMode()方法获取到相应的线程模式
                        ThreadMode threadMode = subscribeAnnotation.threadMode();
                    //9、根据不同的线程模式 进行不同的线程调度操作
                     SubscriberMethod封装的eventbus使用时候所需要的对象添加到FindState 存储方法的集合当中
                        findState.subscriberMethods.add(
                                            new SubscriberMethod(method, eventType, threadMode,
                                subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        …
        }
     
    getMethodsAndRelease():进行返回和释放资源的操作
    private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
        List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
           //进行资源回收
        findState.recycle();
           ...
    }
     
    六、EventBus框架的subscribe 观察者
    目标:根据获取到方法的集合单个方法的获取工作
    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = 
      //完成注册订阅的第一步:
    subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        //下面的目标是:遍历订阅好的方法集合 ,进行每个方法的订阅操作
     
        //建立同步代码块
        synchronized (this) { 
                //遍历获取到的方法集合——
    ps:在上一版本中 是通过 获取subscriberMethods的迭代器 ,然后while循环不断的遍历这个迭代器(迭代器.hasNext())
        
        //增强for循环 不断遍历获取到每一个订阅方法
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
               //完成订阅的第二步:调用该方法完成订阅 
    ps:
               parameter:订阅者-subscriber
               parameter:订阅方法-subscriberMethod
                subscribe(subscriber, subscriberMethod);
            }
        }
    }
            
    subscribe():
    主体流程:
    •     1、首先判断是否有注册过该事件;有注册过抛出异常
    •     2、按照优先级顺序加入到 subscriptionsByEventType的 value的List中;通过这个HashMap 找到该事件的订阅者、
    • 订阅的方法和参数 等等
    •     3、再添加到typesBySubscriber的value的List中;通过这个HashMap可以使订阅者找到该订阅者订阅的所有事件
    •     4、判断是否是粘性事件、是否有继承关系
    •     5、调用checkPostStickyEventToSubscription进行事件的的分发
     
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
       //首先获取订阅方法的 事件类型 eventType属性
        Class<?> eventType = subscriberMethod.eventType;
     
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
       ps:Subscription内部封装了 subscriber订阅者 和 subscriberMethod 订阅方法;
    而subscriberMethod又封装了订阅的方法,线程模式,事件类型,优先级,是否是粘性事件等属性。
    所以在这里可以看出Subscription 是一个更大的封装类而已
     
    //subscriptionsByEventType这个HashMap的key就是eventType,而value就是subscriptions
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    ps:CopyOnWriteArrayList 是一个可以并发读写的arrayList
     
    //如果subscriptions 为空null,表明这个事件还没有被注册过
    if (subscriptions == null) {
           //新创建一个arrayList 并把这个arraylist放入到 subscriptionsByEventType 这个HashMap当中
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);//为了后期复用
    //如果这个 subscriptions当中包含了新创建好的newSubscription的话就会抛出异常 ;
    异常信息是 该订阅者 已经注册过了该事件 +该事件的类型
    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) {
         //根据优先级添加到arrayList当中的制定位置
             subscriptions.add(i, newSubscription);
            break;
        }
    }
    //以订阅者subscriber为key,以eventType为value,来获取到eventType 的arrayList
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
       //新创建一个并填入typesBySubscriber这个HashMap当中
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
       //将这个事件类型放入到eventType的arrayList当中
    subscribedEvents.add(eventType);
     
        //判断订阅方法是否为粘性事件,进一步判断是否支持继承关系
    if (subscriberMethod.sticky) {
        if (eventInheritance) {
       //根据entrySet() 函数获取所有粘性事件的Set集合
    Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
       //依次遍历 并通过eventType.isAssignableFrom()再次判断是否有继承关系
    for (Map.Entry<Class<?>, Object> entry : entries) {
        Class<?> candidateEventType = entry.getKey();
        if (eventType.isAssignableFrom(candidateEventType)) {
            Object stickyEvent = entry.getValue();
        //如果有继承关系的话,进行事件的分发操作
            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
        }
    }
     
    checkPostStickyEventToSubscription():
    private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        if (stickyEvent != null) {
            postToSubscription(newSubscription, stickyEvent,
                    Looper.getMainLooper() == Looper.myLooper() );//通过该标志位判断是否在主线程当中
        }
    }
     
    postToSubscription(): 核心方法使用的是 线程调度的 三个 post 方法
    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING: 
            //如果处于POSTING 默认模式 就直接完成线程调用
                invokeSubscriber(subscription, event);
                break;
            case MAIN: 
           //如果处于Ui主线程中,就直接调用invokeSubscriber
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
           //如果不是在主线程,通过handlerPost中的enqueue方法 把需要的 ()入到队列当中
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case BACKGROUND:
                if (isMainThread) {
           //如果在Ui线程 ,就需要通过background 入队列
                    backgroundPoster.enqueue(subscription, event);
                } else {
            //如果不在UI线程,区别于MAIN ,可以直接调用
                    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);
        }
    }
     
    七、EventBus框架的Post事件发送 -核心的线程调度
    EventBus.getDefault().post(new MyBusEvent("test fot eventbus"));
    public void post(Object event) {
       //通过ThreadLocal 获取到一个发送状态 postingThreadState
        PostingThreadState postingState = currentPostingThreadState.get();
        ps:PostingThreadState 发送事件的线程类的封装类;
        currentPostingThreadState 就是一个ThreadLocal ,线程独有的,不会让其他线程共享当前线程的数据
     
       //获取到事件队列,并将这个事件添加到队列当中
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);
       //判断是否在进行发送状态,如果发送了就取消操作
        if (!postingState.isPosting) {
           //获取到Looper判断是否在主线程,获取到当前线程的Looper 和主线程的Looper然后进行对比,如果对比结果isMainThread为true 就继续下面的操作
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            //将isPosting设为true 表示这个事件正在分发了
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
               //直到整个队列都为空,如果队列不为空则用postSingleEvent()发送事件
                while (!eventQueue.isEmpty()) {
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
            //将发生状态清零
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }
     
    postSingleEvent():
    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        //是否查看与这个事件有关的继承关系 
        if (eventInheritance) {
           //查找到所有继承关系的事件类型
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
     
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
    //如果没有任何的事件,就会调用post(new NoSubscriberEvent() ),表明没有订阅者订阅该事件
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                Log.d(TAG, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }
     
    postSingleEventForEventType()://获取subscriptionFound 标志位
    private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
           //在同步代码块中,通过sbuscriptionsByEventType的HashMap,获取到一个订阅event事件的集合
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        …
        //完成订阅-核心的三个post调度方法
        postToSubscription(subscription, event, postingState.isMainThread);
        aborted = postingState.canceled;
        …
    }
     
  • 相关阅读:
    jekins安装
    Nginx启动、关闭命令
    win10启动docker desktop报错
    CSS设置背景图片
    Lucene 8.5.2核心API
    Lucene 8.5.2演示API
    html+css实现选项卡效果
    搞懂JavaScript全局变量与局部变量,看这篇文章就够了
    你不知道的CSS妙用,纯CSS实现炫酷照片墙
    JS中!function(){}()的理解
  • 原文地址:https://www.cnblogs.com/cold-ice/p/9466858.html
Copyright © 2020-2023  润新知