当前位置: 首页 > 工具软件 > EventBus > 使用案例 >

EventBus解析并实现手写EventBus

宰父阳焱
2023-12-01

前言

其实在我们开发当中需要应用组件与后台线程间进行通信,比如在子线程中进行请求数据,当数据请求完毕后通过Handler或者是广播通知UI,而两个Fragment之家可以通过Listener进行通信等等。当我们的项目越来越复杂,使用Intent、Handler、Broadcast进行模块间通信、模块与后台线程进行通信时,代码量大,而且高度耦合;最近公司正在做了一款项目是要求模块化来做,前期考虑是想用阿里的ARouter实现模块间的跳转和传值,因为我们公司App设计是一个Activity其别的页面都是显示用Fragment去展示的,考虑到返回容器的处理觉得ARouter不适合,就选择了EventBus来实现模块间的跳转和传值,下面带大家了解下EventBus。

什么是EventBus?

EventBus是Android和Java的发布/订阅事件总线;
事件总线是对发布–订阅模式的一种实现。他是一种集中式事件处理机制,允许不同的组件之间彼此通信而不需要相互依赖,达到解耦的目的。

三要素

一:Event 事件;
二:Subscriber 事件订阅者;
三:Publisher 事件发布者;

四种线程模型

POSTING (默认) 表示事件处理函数的线程跟发布事件的线程在同一个线程;
MAIN 表示事件处理函数的线程在主线程(UI)线程,因此在这里不能进行耗时操作;
BACKGROUND 表示事件处理函数的线程在后台线程,因此不能进行UI操作。如果发布事件的线程是主线程(UI线程),那么事件处理函数将会开启一个后台线程,如果果发布事件的线程是在后台线程,那么事件处理函数就使用该线程;
ASYNC 表示无论事件发布的线程是哪一个,事件处理函数始终会新建一个子线程运行,同样不能进行UI操作;

EventBus优点

一: 代码简单,快;
二:jar包小;
三:Activity、Fragment以及线程间通信优秀;
四:稳定;

上面简单了解了一下EventBus下面我们就手动实现下:
第一步我们先注册,为了区别官方我们定义MyEventBus
 MyEventBus.getDefault().register(this);
二:定义一个实现数据回调的方法
   @Subscrible(threadMode = ThreadMode.MAIN)//线程为主线程
    public void getMessage(EventBean eventBean){
        Toast.makeText(MainActivity.this,eventBean.toString(),Toast.LENGTH_SHORT).show();
        Log.e("main", eventBean.toString());
    }
三:我们先创建一个注解处理器
@Target(ElementType.METHOD)//注解到方法上面
@Retention(RetentionPolicy.RUNTIME)//定义运行时
public @interface Subscrible {
    //
    ThreadMode threadMode() default ThreadMode.MAIN;
}
四:写个枚举来区分线程
public enum ThreadMode {
    MAIN,
    BACHGROUND
}
五:接收方法参数为bean类
public class EventBean {
    private String name;
    private String msg;

    public EventBean(final String name, final String msg) {
        this.name = name;
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "EventBean{" +
                "name='" + name + '\'' +
                ", msg='" + msg + '\'' +
                '}';
    }
}

六:开始来写核心代码
public class MyEventBus {
    //定义一个容器来存放方法
    private Map<Object, List<SubscribleMethod>> cacheMap;
   private Handler mHandler;
    private static volatile MyEventBus instance;

    private MyEventBus() {
        cacheMap = new HashMap<>();
        mHandler = new Handler();
    }
    public static MyEventBus getDefault() {
        if (instance == null) {
            synchronized (MyEventBus.class) {
                if (instance == null) {
                    instance = new MyEventBus();
                }
            }
        }
        return instance;
    }
    //  在这个方法中去判断所有当前类的所有方法
    public void register(Object obj) {
//      首先在map集合取当前类的集合
        List<SubscribleMethod> list = cacheMap.get(obj);
        if (list == null) {
//            定义方法取
            list = findSubscribleMethods(obj);
//            存到容器
            cacheMap.put(obj, list);
        }

    }
    private List<SubscribleMethod> findSubscribleMethods(final Object obj) {
//        定义一个集合
        List<SubscribleMethod> list = new ArrayList<>();
//
        Class<?> aClass = obj.getClass();
//        可以得到当前类的所有方法 此方法获取不带父类的方法
        Method[] methods = aClass.getDeclaredMethods();
//        //            若是取父类的方法 用下面方法
//        Method[] methods1 = aClass.getMethods();
        while (aClass != null) {//此循环是向父类一层层往上找
//            找父类的时候是要先判断下是否是系统级别的父类
            String name = aClass.getName();
//            判断是系统级别的名字就停止
            if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
                break;
            }
            //        遍历所有方法
            for (Method method : methods) {
//            找到带Subscrible注解的方法,
                Subscrible subscrible = method.getAnnotation(Subscrible.class);
                if (subscrible == null) {
                    continue;
                }
//            获取subscrible的参数类型
                Class<?>[] types = method.getParameterTypes();
//       不为空的时候就判断下带有subscrible注解的方法参数类型
                if (types.length == 1) {

                }
                ThreadMode threadMode = subscrible.threadMode();
                SubscribleMethod subscribleMethod = new SubscribleMethod(method, threadMode, types[0]);
                list.add(subscribleMethod);
            }
            //  等于父类的类
            aClass =aClass.getSuperclass();
        }

        return list;
    }

    //  发送evengtbus的方法
    public void post(final Object type) {
//        直接循环map里面的方法,找到对应的然后调用
        Set<Object> set = cacheMap.keySet();
        Iterator<Object> iterator = set.iterator();//迭代器
        while (iterator.hasNext()){//循环
            final Object obj = iterator.next();
            List<SubscribleMethod> list = cacheMap.get(obj);//得到集合
            for (final SubscribleMethod subscribleMethod:list) {//遍历
//                判断方法的参数是否相等
                if (subscribleMethod.getType().isAssignableFrom(type.getClass())){
//                    判断下线程
                    switch (subscribleMethod.getThreadMode()){
                        case MAIN:
                            //主线程到  主线程
                            if (Looper.myLooper() == Looper.getMainLooper()){
                                invoke(subscribleMethod,obj,type);
                            }else {
//                                从子线程到主线程
                                mHandler.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        invoke(subscribleMethod,obj,type);
                                    }
                                });
                            }
                            break;
                        case BACHGROUND:  //后续添加
                                break;
                    }
                }
            }
        }
    }
//    是一个回调的方法
    private void invoke(final SubscribleMethod subscribleMethod, final Object obj, final Object type) {
        Method method = subscribleMethod.getMethod();
        try {
            method.invoke(obj,type);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
总结

上面代码主要是实现一个简单的EventBus实现数据传递,因为源码里面还有好多方法后续会陆续添加,也希望更多的小伙伴多多提下意见,共同进步下面给大家提供本人github地址本人已经上传望大家共同改进。

本篇github传送门
 类似资料: