Android知名三方库EventBus手写实现

源代码
GitHub源代码

本文目标

实现简易版的EventBus

基本用法

现在有两个页面,MainActivity 和 TestActivity,在MainActivity中注册EventBus事件,然后在TestActivity中发射事件

public class MainActivity extends AppCompatActivity {

    private TextView mTv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 注册
        EventBus.getDefault().register(this);

        // 进入测试界面
        mTv = (TextView) findViewById(R.id.test_tv);
        mTv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,TestActivity.class);
                startActivity(intent);
            }
        });
    }

    /**
     * threadMode 执行的线程方式
     * priority 执行的优先级
     * sticky 粘性事件
     */
    @Subscribe(threadMode = ThreadMode.MAIN,priority = 50,sticky = true)
    public void test1(String msg){
        // 如果有一个地方用 EventBus 发送一个 String 对象,那么这个方法就会被执行
        Log.i("TAG","msg1 = "+msg);
        mTv.setText(msg);
    }

    /**
     * threadMode 执行的线程方式
     * priority 执行的优先级,值越大优先级越高
     * sticky 粘性事件
     */
    @Subscribe(threadMode = ThreadMode.MAIN,priority = 100,sticky = true)
    public void test2(String msg){
        // 如果有一个地方用 EventBus 发送一个 String 对象,那么这个方法就会被执行
        Log.i("TAG","msg2 = "+msg);
        mTv.setText(msg);
    }

    @Override
    protected void onDestroy() {
        // 解绑
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }
}

在TestActivity中去发射事件

public class TestActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);

        findViewById(R.id.test_tv).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().post("今天天气真晴朗");
                finish();
            }
        });
    }
}

手写之前明确几个基本概念

在手写之前一定要先弄明白EventBus中的两个字段(两个map)

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
上面这个字段是个map集合
|-- key: Event函数的参数的类(本例中是String.class)
|-- value: Subscription 的集合列表
|-- Subscription包含两个属性
|-- 一个是subscriber 订阅者(反射执行对象,本例中是MainActivity.class)
|-- 一个是SubscriberMethod 注解方法的所有属性参数值(threadModel线程模型 priority优先级 sticky是否黏性 eventType事件类型class method方法对象)

private final Map<Object, List<Class<?>>> typesBySubscriber;
上面这个字段是个map集合,主要用于解绑使用
|-- key: 所有的订阅者(本例中是MainActivity.class)
|-- value: 所有订阅者里面方法的参数的class() (本例中是 String.class 的集合)
目的是在unregister()解绑中通过key(MainActivity.class)找到value(String.class),
然后在通过value(String.class)找到subscriptionsByEventType中的value()Subscription 的集合列表,
然后就可以进行移除操作了

上述两个map是在EventBus的构造方法中去实现的

public class EventBus {

    // key 是 Event 参数的类(本例中是String.class)
    // value 存放的是 Subscription 的集合列表
    // Subscription 包含两个属性,一个是 subscriber 订阅者(反射执行对象,本例中是MainActivity.class),一个是 SubscriberMethod 注解方法的所有属性参数值
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;

    // key 是所有的订阅者(MainActivity.class)
    // value 是所有订阅者里面方法的参数的class() (本例中就是 String.class 的集合)
    private final Map<Object, List<Class<?>>> typesBySubscriber;

    private EventBus() {
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
    }

    private volatile static EventBus INSTANCE = null;

    public static EventBus getDefault() {
        if (INSTANCE == null) {
            synchronized (EventBus.class) {
                if (INSTANCE == null) {
                    INSTANCE = new EventBus();
                }
            }
        }
        return INSTANCE;
    }
}

1.EventBus.getDefault().register()

    public void register(Object object) {
        //第一步
        ArrayList<SubscriberMethod> subscriberMethods = new ArrayList<>();
        //1.先拿到object的字节码class对象
        Class<?> objectClass = object.getClass();
        Method[] declaredMethods = objectClass.getDeclaredMethods();
        for (Method method : declaredMethods) {
            //2.获取到该class对象的所有标记@Subscribe注解的函数
            Subscribe annotation = method.getAnnotation(Subscribe.class);
            if(annotation!=null){
                // 所有的Subscribe属性 解析出来
                Class<?>[] parameterTypes = method.getParameterTypes();
                //3.解析被注解标记的函数成SubscriberMethod对象(threadModel线程模型 priority优先级 sticky是否黏性 eventType事件类型class method方法对象)
                SubscriberMethod model = new SubscriberMethod(method, parameterTypes[0], annotation.threadMode(), annotation.priority(), annotation.sticky());
                //4.然后存到subscriberMethods集合中
                subscriberMethods.add(model);
            }
        }
        //第二步
        //1.遍历subscriberMethods的List集合
        for (SubscriberMethod method : subscriberMethods) {
            subscribe(object,method);
        }
    }

    private void subscribe(Object object, SubscriberMethod method) {
        //2.按照规则存放到subscriptionsByEventType的map集合中(key:String.class  value:CopyOnWriteArrayList<Subscription>)
        Class<?> eventType = method.eventType;
        //先从subscriptionsByEventType 的map中取一下List,如果为空则创建一个,然后在添加
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if(subscriptions==null){
            subscriptions=new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType,subscriptions);
        }
        Subscription subscription = new Subscription(object, method);
        subscriptions.add(subscription);

        //第三步:
        //1.typesBySubscriber的map集合也要存一份(key:MainActivity.class value:List<Class<?> String.class 的集合)
        List<Class<?>> eventTypeList = typesBySubscriber.get(object);
        if(eventTypeList==null){
            eventTypeList=new ArrayList<>();
            typesBySubscriber.put(object,eventTypeList);
        }
        if(!eventTypeList.contains(eventType)){
            eventTypeList.add(eventType);
        }
    }

register的核心思路
第一步:

  • 1.先拿到object的字节码class对象
  • 2.获取到该class对象的所有标记@Subscribe注解的函数
  • 3.解析被注解标记的函数成SubscriberMethod对象(threadModel线程模型 priority优先级 sticky是否黏性 eventType事件类型class method方法对象)
  • 4.然后存到subscriberMethods集合中
    第二步:
  • 1.遍历subscriberMethods的List集合
  • 2.按照规则存放到subscriptionsByEventType的map集合中(key:String.class value:CopyOnWriteArrayList<Subscription>)
    第三步:
  • 1.typesBySubscriber的map集合也要存一份(key:MainActivity.class value:List<Class<?> String.class 的集合)

2.EventBus.getDefault().unregister()

    public void unregister(Object object) {
        //1.通过typesBySubscriber这个map得到所有的String.class集合
        List<Class<?>> eventTypList = typesBySubscriber.get(object);
        if(eventTypList!=null){
            //2.遍历这个String.class集合
            for (Class<?> eventType : eventTypList) {
                removeObject(eventType,object);
            }
        }
    }

    private void removeObject(Class<?> eventType, Object object) {
        //3.通过subscriptionsByEventType这个map获取到CopyOnWriteArrayList<Subscription>
        CopyOnWriteArrayList<Subscription> subscriptionList = subscriptionsByEventType.get(eventType);
        if(subscriptionList!=null){
            int size = subscriptionList.size();
            //4.遍历CopyOnWriteArrayList集合,然后挨个移除
            for(int x=0;x<size;x++){
                //5.得到Subscription,然后subscription.subscriber==object 进行比较,如果相同则移除
                Subscription subscription = subscriptionList.get(x);
                if(subscription.subscriber==object){
                    subscriptionList.remove(x);
                    x--;
                    size--;
                }
            }
        }
    }

unregister的核心思路

  • 1.通过typesBySubscriber这个map得到所有的String.class集合
  • 2.遍历这个String.class集合
  • 3.通过subscriptionsByEventType这个map获取到CopyOnWriteArrayList<Subscription>
  • 4.遍历CopyOnWriteArrayList集合
  • 5.得到Subscription,然后subscription.subscriber==object 进行比较,如果相同则移除

3.EventBus.getDefault().post()

public void post(Object event) {
        //1.先获取event的字节码对象,这其实就是eventType
        Class<?> evenType = event.getClass();
        //2.从subscriptionsByEventType中根据eventType得到Subscription 的集合列表
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(evenType);
        if(subscriptions!=null){
            //3.遍历这个集合
            for (Subscription subscription : subscriptions) {
                executeMethod(subscription,event);
            }
        }
    }

    //4.找到符合的方法调用方法的 method.invoke() 执行,要注意线程切换
    private void executeMethod(final Subscription subscription, final Object event) {
        SubscriberMethod subscriberMethod = subscription.subscriberMethod;

        //是否在主线程
        boolean isMainThread = Looper.getMainLooper() == Looper.myLooper();
        switch (subscriberMethod.threadMode){
            //同一个线程,在哪个线程发送事件,那么该方法就在哪个线程执行
            case POSTING:
                invokeMethod(subscription,event);
                break;

                // 在主线程中执行
            case MAIN:
                if(isMainThread){
                    invokeMethod(subscription,event);
                }else{
                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            invokeMethod(subscription,event);
                        }
                    });
                }
                break;

                //子线程:如果发布事件的线程是主线程,那么调用线程池中的子线程来执行订阅方法;否则直接执行;
            case BACKGROUND:
                if(isMainThread){
                    AsyncPoster.enqueue(subscription,event);
                }else{
                    invokeMethod(subscription,event);
                }
                break;

                //异步线程:无论发布事件执行在主线程还是子线程,都利用一个异步线程来执行订阅方法。
            case ASYNC:
                AsyncPoster.enqueue(subscription,event);
                break;

            default:
                break;
        }

    }

    /**
     * 真正的反射调用方法
     * @param subscription
     * @param event
     */
    private void invokeMethod(Subscription subscription, Object event) {
        try {
            subscription.subscriberMethod.method.invoke(subscription.subscriber,event);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

post的核心思路

  • 1.先获取event的字节码对象,这其实就是eventType
  • 2.从subscriptionsByEventType中根据eventType得到Subscription 的集合列表
  • 3.遍历这个集合
  • 4.找到符合的方法调用方法的 method.invoke() 执行,要注意线程切换

下面的代码是一些辅助代码,核心的代码都在上面

线程池的使用

public class AsyncPoster implements Runnable {
    final Subscription subscription;
    final Object event;

    private final static ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    public AsyncPoster(Subscription subscription, Object event) {
        this.subscription = subscription;
        this.event = event;
    }

    public static void enqueue(final Subscription subscription, final Object event) {
        AsyncPoster asyncPoster = new AsyncPoster(subscription, event);
        // 用线程池
        EXECUTOR_SERVICE.execute(asyncPoster);
    }

    @Override
    public void run() {
        try {
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

@Subscribe注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;

    /**
     * 是否是黏性事件
     * @return
     */
    boolean sticky() default false;

    /**
     * 优先级,值越大优先级越高
     * @return
     */
    int priority() default 0;
}

线程模型

public enum ThreadMode {

    /**
     * 同一个线程,在哪个线程发送事件,那么该方法就在哪个线程执行
     */
    POSTING,

    /**
     * 在主线程中执行
     */
    MAIN,

    /**
     * 子线程:如果发布事件的线程是主线程,那么调用线程池中的子线程来执行订阅方法;否则直接执行;
     */
    BACKGROUND,

    /**
     * 异步线程:无论发布事件执行在主线程还是子线程,都利用一个异步线程来执行订阅方法。
     */
    ASYNC
}

Subscription 包装类

final class Subscription {
    final Object subscriber; //反射执行对象,本例中是MainActivity.class
    final SubscriberMethod subscriberMethod;//方法上解析的所有信息包装类
    volatile boolean active;

    Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
        this.subscriber = subscriber;
        this.subscriberMethod = subscriberMethod;
        active = true;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof Subscription) {
            Subscription otherSubscription = (Subscription) other;
            return subscriber == otherSubscription.subscriber
                    && subscriberMethod.equals(otherSubscription.subscriberMethod);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
    }
}

Subscription包含两个属性
|-- 一个是subscriber 订阅者(反射执行对象,本例中是MainActivity.class)
|-- 一个是SubscriberMethod 注解方法的所有属性参数值(threadModel线程模型 priority优先级 sticky是否黏性 eventType事件类型class method方法对象)

SubscriberMethod 包装类

public class SubscriberMethod {
    final Method method;//method方法对象
    final ThreadMode threadMode;//线程模型
    final Class<?> eventType;//事件类型class
    final int priority;//优先级
    final boolean sticky;//是否黏性
    /** Used for efficient comparison */
    String methodString;

    public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
        this.method = method;
        this.threadMode = threadMode;
        this.eventType = eventType;
        this.priority = priority;
        this.sticky = sticky;
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        } else if (other instanceof SubscriberMethod) {
            checkMethodString();
            SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
            otherSubscriberMethod.checkMethodString();
            // Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
            return methodString.equals(otherSubscriberMethod.methodString);
        } else {
            return false;
        }
    }

    private synchronized void checkMethodString() {
        if (methodString == null) {
            // Method.toString has more overhead, just take relevant parts of the method
            StringBuilder builder = new StringBuilder(64);
            builder.append(method.getDeclaringClass().getName());
            builder.append('#').append(method.getName());
            builder.append('(').append(eventType.getName());
            methodString = builder.toString();
        }
    }

    @Override
    public int hashCode() {
        return method.hashCode();
    }
}

注解方法的所有属性参数值的封装类(threadModel线程模型 priority优先级 sticky是否黏性 eventType事件类型class method方法对象)

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容