码迷,mamicode.com
首页 > 移动开发 > 详细

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

时间:2018-08-13 12:12:34      阅读:181      评论:0      收藏:0      [点我收藏+]

标签:主线程   步骤   bye   一次循环   mode   sid   返回   现象   i++   

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

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

标签:主线程   步骤   bye   一次循环   mode   sid   返回   现象   i++   

原文地址:https://www.cnblogs.com/cold-ice/p/9466858.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!