当前位置:   article > 正文

手写EventBus

手写eventbus

前言

EventBus是一种用于Android的事件发布-订阅总线,由GreenRobot开发,Gihub地址是:EventBus。它简化了应用程序内各个组件之间进行通信的复杂度,尤其是碎片之间进行通信的问题,可以避免由于使用广播通信而带来的诸多不便。

像这样的框架如何进行实现呢,我们就手写一个。

工程目录结构
在这里插入图片描述

一,定义枚举类

枚举类,用于线程切换。

public enum ThreadMode {
    MAIN,BACKGROUND
}
  • 1
  • 2
  • 3

二,注解类

注解@Target:用于描述注解的使用范围,ElementType.METHOD,用于描述方法。
注解@Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期。RetentionPolicy.RUNTIME,代表在运行时有效。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Subscribe {
 ThreadMode threadMode() default ThreadMode.MAIN;
}
  • 1
  • 2
  • 3
  • 4
  • 5

三,实体类

用于存放方法和类

public class SubscribeMethod {
    //回调方法
    private Method mMethod;
    //线程模式
    private ThreadMode mThreadMode;
    //方法中的参数
    private Class<?> type;

    public SubscribeMethod(Method mMethod, ThreadMode mThreadMode, Class<?> type) {
        this.mMethod = mMethod;
        this.mThreadMode = mThreadMode;
        this.type = type;
    }

    public Method getmMethod() {
        return mMethod;
    }

    public void setmMethod(Method mMethod) {
        this.mMethod = mMethod;
    }

    public ThreadMode getmThreadMode() {
        return mThreadMode;
    }

    public void setmThreadMode(ThreadMode mThreadMode) {
        this.mThreadMode = mThreadMode;
    }

    public Class<?> getType() {
        return type;
    }

    public void setType(Class<?> type) {
        this.type = type;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

发送消息实体类

public class EventBean {
    private int state;
    private String message;
    public EventBean(int state, String message) {
        this.state = state;
        this.message = message;
    }
    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return "EventBean{" +
                "state=" + state +
                ", message='" + message + '\'' +
                '}';
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

四,消息发送和接收实现类

public class EventBus {
    private Map<Object, List<SubscribeMethod>> cacheMap;
    private Handler mHander;
    private static volatile EventBus instance;

    private EventBus() {
        cacheMap = new HashMap<>();
        mHander=new Handler();
    }

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

    public void register(Object object) {
        List<SubscribeMethod> list = cacheMap.get(object);
        if (list == null) {
            list = findSubscribeMethods(object);
            cacheMap.put(object, list);
        }
    }

    private List<SubscribeMethod> findSubscribeMethods(Object object) {
        List<SubscribeMethod> list = new ArrayList<>();
        Class<?> clazz = object.getClass();
        Method[] methods = clazz.getDeclaredMethods();
        while (clazz != null) {
            //找父类的时候,需要先判断是否是系统级别父类
            String name = clazz.getName();
            if (name.startsWith("java.") || name.startsWith("javax.")
                    || name.startsWith("android.")) {
                break;
            }
            for (Method method : methods) {
                //找到带有Subcribe注解的方法
                Subscribe subscribe = method.getAnnotation(Subscribe.class);
                if (subscribe == null) {
                    continue;
                }
                Class<?>[] types = method.getParameterTypes();
                if (types.length != 1) {
                    Log.e("EventBus", "findSubscribeMethods: 错误");
                }
                ThreadMode threadMode = subscribe.threadMode();
                SubscribeMethod subscribeMethod = new SubscribeMethod(method, threadMode, types[0]);
                list.add(subscribeMethod);
            }
            clazz = clazz.getSuperclass();
        }

        return list;
    }

    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<SubscribeMethod> list = cacheMap.get(obj);
            for (final SubscribeMethod subscribeMethod : list) {
                if (subscribeMethod.getType().isAssignableFrom(type.getClass())) {
                    switch (subscribeMethod.getmThreadMode()) {
                        case MAIN:
                            if (Looper.myLooper() == Looper.getMainLooper()) {
                                invoke(subscribeMethod, obj, type);
                            }else{
                                mHander.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        invoke(subscribeMethod, obj, type);
                                    }
                                });
                            }
                            break;
                        case BACKGROUND:
                            break;
                    }
                }
            }
        }
    }

    private void invoke(SubscribeMethod subscribeMethod, Object obj, Object type) {
        Method method = subscribeMethod.getmMethod();
        try {
            method.invoke(obj, type);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

五,使用方法

在MainActivity 中注册并接收消息

public class MainActivity extends AppCompatActivity {

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

        Intent intent = new Intent(this, SecondActivity.class);
        startActivity(intent);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void getMessage(EventBean bean) {
        Log.i("MainActivity", "getMessage: bean=" + bean.toString());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在SecondActivity 中发送消息

public class SecondActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second_activity);
        findViewById(R.id.second_tv).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().post(new EventBean(1001,"你好"));
            }
        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

很简单的实现方式,当然在实际开发中还需要更多的代码,去完善EventBus。这里只说明了,用最简单的方式去实现一个EventBus,核心思想就是注解和反射,很好理解。

六,EventBus 实现原理

https://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650264045&idx=1&sn=08ec3b416144a435fb557d51007c137c&chksm=88632082bf14a994b3bb10b63185c32b39e855e40103434a52fe6066254e96ae7718c29eccd4&scene=27

EventBus 是一种事件发布/订阅框架,它实现了发布/订阅模式,提供了一种异步的、松散耦合的消息传递机制。

EventBus 的主要实现机制还是基于反射和编译时注解(APT),一句话概括就是:

  • 注册时传入目标类对象,然后利用反射筛选出 @Subscribe 的方法,然后以相同的参数类型为 key,将不同的方法合并为 list 作为
    value,得到一个 map 集合。
  • 当用户 post 数据时,再以数据类型为 key,从 map 中取出对应的方法 list,然后遍历
    list,再利用反射机制对指定的方法执行 invoke 操作,完成调用。

EventBus 如何切回主线程的:

EventBus在初始化的时候会初始化一个MainThreadSupport对象,它会去获取主线程的Looper对象并存起来。这个mainThreadPoster其实是Handler的子类,它利用Handler的消息机制切换线程。

APT(Annotation Processing Tool)

是一种编译时注解处理工具,它可以在编译 Java 代码时扫描指定的注解,并根据注解生成相应的代码。APT 可以帮助开发者在编译时自动生成代码,减少重复劳动,提高代码的复用性和可维护性。

APT 的工作原理如下:

  • 在编译 Java 代码时,APT 会扫描源代码文件,并检查源代码中的注解。
  • 当 APT 检测到注解时,它会根据注解的定义生成相应的代码,并将生成的代码保存到指定的输出目录中。
  • 编译器会将生成的代码编译成字节码文件,与源代码一起打包成一个 JAR 文件或类文件。
  • 在运行时,应用程序可以使用生成的代码,实现相应的功能。

APT 可以帮助开发者自动生成很多有用的代码,例如自动生成代码检查器、数据库映射器、事件监听器等。APT 还可以与其他框架和工具结合使用,例如与 Dagger、ButterKnife 等依赖注入框架结合使用,可以大大简化代码的编写和维护工作。

七,JAVA注解原理

Java注解是一种用于提供元数据的Java语言特性。它们允许在Java代码中添加额外的信息,这些信息可以用于编译时检查、运行时处理或者生成代码。注解可以应用于类、方法、字段和其他程序元素。

Java注解的原理可以通过以下步骤来理解:

1.定义注解:使用@interface关键字定义一个注解。注解本质上是一个接口,其中的方法称为成员。成员可以有默认值,也可以没有。

public @interface MyAnnotation {
    String value() default "default value";
    int count() default 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5

2.注解的使用:在代码中使用注解,可以用于修饰类、方法、字段等。可以为注解的成员赋值。

@MyAnnotation(value = "Hello", count = 5)
public class MyClass {
    @MyAnnotation(count = 2)
    private int myField;

    @MyAnnotation
    public void myMethod() {
        // 方法体
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3.元数据的获取:使用Java的反射机制可以在运行时获取注解的信息。可以获取注解类型、成员值等。

Class<?> clazz = MyClass.class;
MyAnnotation classAnnotation = clazz.getAnnotation(MyAnnotation.class);
System.out.println(classAnnotation.value()); // 输出:Hello

Field field = clazz.getDeclaredField("myField");
MyAnnotation fieldAnnotation = field.getAnnotation(MyAnnotation.class);
System.out.println(fieldAnnotation.count()); // 输出:2

Method method = clazz.getDeclaredMethod("myMethod");
MyAnnotation methodAnnotation = method.getAnnotation(MyAnnotation.class);
System.out.println(methodAnnotation.value()); // 输出:default value

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

编译时注解和运行时注解是在使用时机和处理方式上有所区别的。

编译时注解(Compile-time Annotations):

  • 定义:编译时注解是在编译阶段处理的注解,它们在源代码被编译成字节码时被读取和处理。
  • 使用:编译时注解通常用于在编译过程中进行静态检查、生成额外的代码或者生成资源文件等。
  • 处理方式:编译时注解的处理是由编译器或自定义的注解处理器负责的,它们会在编译过程中扫描源代码中的注解并进行相应的处理。
  • 示例:常见的编译时注解包括@Override、@Deprecated、@SuppressWarnings等。

运行时注解(Runtime Annotations):

  • 定义:运行时注解是在程序运行时通过反射机制读取和处理的注解。
  • 使用:运行时注解通常用于在运行时进行动态的配置、处理或逻辑判断。
  • 处理方式:运行时注解的处理是通过反射机制来获取注解信息,并根据注解信息进行相应的操作和逻辑判断。
  • 示例:常见的运行时注解包括依赖注入框架中的@Autowired、持久化框架中的@Entity、Web框架中的@RequestMapping等。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/628267
推荐阅读
相关标签
  

闽ICP备14008679号