Android(安卓)手把手教你写EventBus
16lz
2021-01-24
前言
Android EventBus这个知识点呢,我已经写了两篇文章,一篇是Android EventBus3.0使用详情,一篇是Android 浅谈EventBus源码,这两个篇文章讲了它的一个使用,还有源码解析,接下来我们通过自己写一个EventBus,让你更容易理解EventBus的原理,下面来看一看实现步骤
- 定义注解
- 定义线程模式
- 订阅方法封装成SubscribeMethod
- 写一个单例
- 封装订阅者方法
- 注册订阅者
- post发布事件
- 线程模式处理
- 执行订阅者方法
- 销毁注册
定义MySubscrible
首先我们定义一个MySubscrible注解,注解还不知道如何使用的,看我之前写的博客Android 注解(Annotation)的入门与使用(一)和Android 注解(Annotation)的入门与使用(二)
/** * QQ:941556675 * zhy * **/@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface MySubscrible { ThreadMode threadMode() default ThreadMode.MAIN;}
定义线程模式
/** * QQ:941556675 * zhy * **/public enum ThreadMode { MAIN, BACHGROUND}
订阅方法封装成SubscribeMethod
/** * QQ:941556675 * zhy * **/public class SubscribeMethod { private Method method; private ThreadMode threadMode; //方法里面的参数类型 private Class<?> type; public SubscribeMethod(Method method, ThreadMode threadMode, Class<?> type) { this.method = method; this.threadMode = threadMode; this.type = type; } public Method getMethod() { return method; } public void setMethod(Method method) { this.method = method; } public ThreadMode getThreadMode() { return threadMode; } public void setThreadMode(ThreadMode threadMode) { this.threadMode = threadMode; } public Class<?> getType() { return type; } public void setType(Class<?> type) { this.type = type; }}
写一个单例
/** * QQ:941556675 * zhy * **/public class MyEventBus { private Handler mHandler; static volatile MyEventBus defaultInstance; private Map
封装订阅者方法及注册订阅者
/** * QQ:941556675 * zhy * **/public void register(Object obj){ List subscribeMethods = map.get(obj); if(subscribeMethods==null){ subscribeMethods = findSubscriberMethods(obj); map.put(obj,subscribeMethods); } } public List findSubscriberMethods(Object obj){ List list=new ArrayList<>(); Class<?> aClass = obj.getClass(); Method[] declaredMethods = aClass.getDeclaredMethods(); for(Method method:declaredMethods){ //判断该方法是否被MySubscrible注解了 if(method.isAnnotationPresent(MySubscrible.class)){ // 返回该方法的注解在此方法的指定注解类型 MySubscrible annotation = method.getAnnotation(MySubscrible.class); // 添加一些校验 Class<?>[] parameterTypes = method.getParameterTypes(); if(parameterTypes.length!=1){ throw new RuntimeException("方法只能为一个参数"); } ThreadMode threadMode = annotation.threadMode(); // 生成订阅者方法封装对象 SubscribeMethod methodManager = new SubscribeMethod(method, threadMode, parameterTypes[0]); list.add(methodManager); } } return list; }
post发布事件
public void post(final Object obj){ Set
线程模式处理
if (subscribeMethod.getType().isAssignableFrom(obj.getClass())) { switch (subscribeMethod.getThreadMode()) { // 判断线程模式 case MAIN: // 判断当前线程是否是主线程 if(Looper.getMainLooper()==Looper.myLooper()){ invoke(subscribeMethod,object,obj); } else{ // 当前是子线程 handler 是用来切换到主线程的 mHandler.post(new Runnable() { @Override public void run() { invoke(subscribeMethod,object,obj); } }); } break; case BACHGROUND: // 判断当前线程是否是主线程 if(Looper.getMainLooper()==Looper.myLooper()){ // 切换到子线程操作 executorService 是线程池对象 executorService.execute(new Runnable() { @Override public void run() { invoke(subscribeMethod,object,obj); } }); } else{ // 当前是子线程 invoke(subscribeMethod,object,obj); } break; } }
执行订阅者方法
通过反射来执行订阅者方法
private void invoke(SubscribeMethod methodManager, Object object, Object setter) { Method method = methodManager.getMethod(); try { // 通过反射执行方法 method.invoke(object, setter); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }
销毁注册
public void unregister(Object object) { if (object != null && map.get(object) != null && map.get(object).size() > 0) { map.remove(object); } }
以上就是手写EventBus的步骤,接下来我们来看看如何使用
public class Test1 extends AppCompatActivity { TextView btn; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.test); btn= findViewById(R.id.btn); MyEventBus.getDefault().register(this); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(Test1.this,Test2.class)); } }); } @MySubscrible(threadMode =ThreadMode.MAIN) public void test1(Cat cat){ Log.d(TAG, "ThreadMode.MAIN,发送过来数据是:" + cat.getName() + ",线程名:" + Thread.currentThread().getName()); } @MySubscrible(threadMode =ThreadMode.BACHGROUND) public void test2(Cat cat){ Log.d(TAG, "ThreadMode.BACKGROUND,发送过来数据是:" + cat.getName() + ",线程名:" + Thread.currentThread().getName()); } @Override protected void onDestroy() { super.onDestroy(); MyEventBus.getDefault().unregister(this); }}
public class Test2 extends AppCompatActivity { TextView btn; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.test); btn= findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { send1(); } }); } public void send1(){ Log.d("Test2", "发布的线程:" + Thread.currentThread().getName()); Cat cat=new Cat(); cat.setName("猫咪:"+"主线程发布一个事件"); MyEventBus.getDefault().post(cat); } public void send2(){ new Thread(new Runnable() { @Override public void run() { Log.d("Test2", "发布的线程:" + Thread.currentThread().getName()); Cat cat=new Cat(); cat.setName("猫咪:"+"子线程发布一个事件"); MyEventBus.getDefault().post(cat); } }).start(); }}
运行结果:
2018-08-26 07:29:08.330 14646-14646/cn.my.com.mywidget D/Test2: 发布的线程:main2018-08-26 07:29:08.331 14646-14646/cn.my.com.mywidget D/Test1: ThreadMode.MAIN,发送过来数据是:猫咪:主线程发布一个事件,线程名:main2018-08-26 07:29:08.334 14646-14711/cn.my.com.mywidget D/Test1: ThreadMode.BACKGROUND,发送过来数据是:猫咪:主线程发布一个事件,线程名:pool-1-thread-12018-08-26 07:31:57.245 14978-15039/cn.my.com.mywidget D/Test2: 发布的线程:Thread-22018-08-26 07:31:57.247 14978-15039/cn.my.com.mywidget D/Test1: ThreadMode.BACKGROUND,发送过来数据是:猫咪:子线程发布一个事件,线程名:Thread-22018-08-26 07:31:57.247 14978-14978/cn.my.com.mywidget D/Test1: ThreadMode.MAIN,发送过来数据是:猫咪:子线程发布一个事件,线程名:main
Demo地址
更多相关文章
- Android列表小部件(Widget)开发详解
- Android蓝牙API之BluetoothAdapter类(1)
- Android图像处理之Bitmap类
- [置顶] android 多线程Thread,Runnable,Handler,AsyncTask等之间
- Android解决在onCreate()中获取View的width、Height为0的方法
- Android(安卓)ADB 找不到设备的解决方法
- 初学Android,数据存储之SharedPreferences(四十一)
- android 预装第三方apk的方法(非system priv-app)
- Android(安卓)TextView使用HTML处理字体样式、显示图片等