赞
踩
EventBus是一种用于Android的事件发布-订阅总线,由GreenRobot开发,Gihub地址是:EventBus。它简化了应用程序内各个组件之间进行通信的复杂度,尤其是碎片之间进行通信的问题,可以避免由于使用广播通信而带来的诸多不便。
像这样的框架如何进行实现呢,我们就手写一个。
工程目录结构
枚举类,用于线程切换。
public enum ThreadMode {
MAIN,BACKGROUND
}
注解@Target:用于描述注解的使用范围,ElementType.METHOD,用于描述方法。
注解@Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期。RetentionPolicy.RUNTIME,代表在运行时有效。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.MAIN;
}
用于存放方法和类
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; } }
发送消息实体类
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 + '\'' + '}'; } }
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(); } } }
在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()); } }
在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,"你好"));
}
});
}
}
很简单的实现方式,当然在实际开发中还需要更多的代码,去完善EventBus。这里只说明了,用最简单的方式去实现一个EventBus,核心思想就是注解和反射,很好理解。
https://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650264045&idx=1&sn=08ec3b416144a435fb557d51007c137c&chksm=88632082bf14a994b3bb10b63185c32b39e855e40103434a52fe6066254e96ae7718c29eccd4&scene=27
EventBus 是一种事件发布/订阅框架,它实现了发布/订阅模式,提供了一种异步的、松散耦合的消息传递机制。
EventBus 的主要实现机制还是基于反射和编译时注解(APT),一句话概括就是:
EventBus 如何切回主线程的:
EventBus在初始化的时候会初始化一个MainThreadSupport对象,它会去获取主线程的Looper对象并存起来。这个mainThreadPoster其实是Handler的子类,它利用Handler的消息机制切换线程。
APT(Annotation Processing Tool)
是一种编译时注解处理工具,它可以在编译 Java 代码时扫描指定的注解,并根据注解生成相应的代码。APT 可以帮助开发者在编译时自动生成代码,减少重复劳动,提高代码的复用性和可维护性。
APT 的工作原理如下:
APT 可以帮助开发者自动生成很多有用的代码,例如自动生成代码检查器、数据库映射器、事件监听器等。APT 还可以与其他框架和工具结合使用,例如与 Dagger、ButterKnife 等依赖注入框架结合使用,可以大大简化代码的编写和维护工作。
Java注解是一种用于提供元数据的Java语言特性。它们允许在Java代码中添加额外的信息,这些信息可以用于编译时检查、运行时处理或者生成代码。注解可以应用于类、方法、字段和其他程序元素。
Java注解的原理可以通过以下步骤来理解:
1.定义注解:使用@interface关键字定义一个注解。注解本质上是一个接口,其中的方法称为成员。成员可以有默认值,也可以没有。
public @interface MyAnnotation {
String value() default "default value";
int count() default 0;
}
2.注解的使用:在代码中使用注解,可以用于修饰类、方法、字段等。可以为注解的成员赋值。
@MyAnnotation(value = "Hello", count = 5)
public class MyClass {
@MyAnnotation(count = 2)
private int myField;
@MyAnnotation
public void myMethod() {
// 方法体
}
}
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
编译时注解和运行时注解是在使用时机和处理方式上有所区别的。
编译时注解(Compile-time Annotations):
运行时注解(Runtime Annotations):
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。