手动模拟EventBus框架
发布日期:2021-11-09 22:50:28 浏览次数:5 分类:技术文章

本文共 11500 字,大约阅读时间需要 38 分钟。

一、实现原理

1、主要的实现类为EventBus类,用观察者实际模式来实现(),包含三个主要的方法:register、 unregister、post

2、订阅者(一般为activity)通过EventBus的register和unRegister来订阅和取消订阅

3、事件发布者通过post来发布数据,EventBus找到自己缓存的所有订阅者,并找到每一个订阅者的所有方法并执行

二、订阅

1、activity把自己作为订阅者,注册到EventBus中,当事件产生时,会调用activity中指定的方法。为了能准确找到需要被调用的方法,这里需要用到自定义注解。

(1)、注册订阅者,activity的onCreate中调用 EventBus.getDefault().register(this);
(2)、自定义注解的实现

@Target({ElementType.METHOD})   // 注解用到方法上的@Retention(RetentionPolicy.RUNTIME) // 运行时起作用public @interface Subscrible {    ThreadMode threadMode() default ThreadMode.MAIN;}

(3)、订阅者方法的实现

// MainActivity方法放到eventbus中,    // 并不是所有的方法都放进EventBus中    // 而是所有带有自定义注解的方法都放进去    @Subscrible(threadMode = ThreadMode.MAIN)    public void test1(EventBean eb){        Log.d("lixm","MainActivity a ====> EventBean = " + eb);    }    @Subscrible(threadMode = ThreadMode.BACKGROUND)    public void test2(EventBean eb){        Log.d("lixm","MainActivity b ====> EventBean = " + eb);    }    // 测试,这个参数不符合,不能接收到数据    @Subscrible(threadMode = ThreadMode.MAIN)    public void test3(String str){        Log.d("lixm","MainActivity b ====> String = " + str);    }

(4)、EventBus中订阅的实现

EventBus维护一个HashMap对象,key是订阅者对象,value是订阅者对象中带有自定义注解的方法的集合。

三、事件发送

1、事件发送者调用EventBus的post方法

EventBus.getDefault().post(new EventBean(“M1”,“M2”));

2、发送方法的实现

EventBus遍历订阅者集合(hashmap),并取出每一个订阅者的方法的集合,循环执行

四、具体的代码实现

1、订阅者(兼事件发送者)activity

import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.util.Log;import android.view.View;import com.hisign.android.test.R;public class MainActivity extends Activity {    @Override    protected void onCreate( Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_event_bus_main);        EventBus.getDefault().register(this);        findViewById(R.id.btAsync).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                EventBus.getDefault().post(new EventBean("M1","M2"));            }        });        findViewById(R.id.btGo).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Intent intent = new Intent(MainActivity.this,SecondActivity.class);                startActivity(intent);            }        });    }    // MainActivity方法放到eventbus中,    // 并不是所有的方法都放进EventBus中    // 而是所有带有自定义注解的方法都放进去    @Subscrible(threadMode = ThreadMode.MAIN)    public void test1(EventBean eb){        Log.d("lixm","MainActivity a ====> EventBean = " + eb);    }    @Subscrible(threadMode = ThreadMode.BACKGROUND)    public void test2(EventBean eb){        Log.d("lixm","MainActivity b ====> EventBean = " + eb);    }    // 测试,这个参数不符合,不能接收到数据    @Subscrible(threadMode = ThreadMode.MAIN)    public void test3(String str){        Log.d("lixm","MainActivity b ====> String = " + str);    }    @Override    protected void onDestroy() {        super.onDestroy();        //EventBus.getDefault().unRegister(this);    }}
import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.View;import com.hisign.android.test.R;public class SecondActivity extends Activity {    @Override    protected void onCreate( Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_event_bus_second);        EventBus.getDefault().register(this);        findViewById(R.id.btAsync).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                // 这里可以模拟网络加载数据(异步进行)                EventBus.getDefault().post(new EventBean("2-1","2-2"));            }        });    }    @Subscrible(threadMode=ThreadMode.MAIN)    public void a(EventBean eventBean){        // 得到数据来自异步线程,需要在主线程更新UI        Log.d("lixm","SecondActivity a ====> EventBean = " + eventBean);    }}

2、重点:EventBus实现

import android.util.Log;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;/** * 管理类,负责将某个activity的方法添加到其中,其他的activity可以在里面寻找方法并调用 */public class EventBus {    /**     * 用于缓存订阅者注册进来的方法     * Object 订阅者     * List
订阅者的方法的集合 * SubscribleMethod 订阅者的方法的封装类 */ private Map
> cacheMap; private static EventBus instance; private EventBus() { cacheMap = new HashMap<>(); } public static EventBus getDefault() { if (instance == null) { synchronized (EventBus.class) { if (instance == null) { instance = new EventBus(); } } } return instance; } /** * 注册,把订阅者(观察者)注册进来 * @param object 订阅者类 */ public void register(Object object) { // 寻找object类中,所有带有subscirble注解的方法 List
list = cacheMap.get(object); // 判断是否订阅 Log.d("lixm", "register(),list = " + list); if (list == null) { list = findSubscribleMethods(object); Log.d("lixm", "register(),findSubscribleMethods--> list = " + list.toString()); cacheMap.put(object, list); } } /** * 在指定类中查找带有自定义注解的方法 * * @param object 观察者类 * @return */ private List
findSubscribleMethods(Object object) { List
list = new ArrayList<>(); Class
clazz = object.getClass(); Log.d("lixm", "findSubscribleMethods(),clazz = " + clazz.getName()); while (clazz != null) { // 循环找,不但找自己类中的,还要找父类中的 String className = clazz.getName(); if (className.startsWith("java.") // 但如果是系统的类中,肯定没有我们自定义的注解,所以不需要解析 || className.startsWith("javax.") || className.startsWith("android.")) { break; } // 得到类中的所有方法 Method[] methods = clazz.getDeclaredMethods(); if (methods != null && methods.length > 0) { for (Method method : methods) { // 只找带有subscrible注解的方法 Subscrible subscrible = method.getAnnotation(Subscrible.class); Log.d("lixm", "method = " + method + ", subscrible = " + subscrible); if (subscrible == null) { continue; } Class
[] types = method.getParameterTypes(); // 该对象表示的方法参数的类型 if (types != null) { if (types.length != 1) { Log.d("lixm", "only one param"); } else { String paramName = types[0].getName(); Log.d("lixm", "paramName = " + paramName); if(types[0].getName().equals(EventBean.class.getName())){ // 根据参数的类型来匹配,参数必须是自己指定的类型 ThreadMode threadMode = subscrible.threadMode(); SubscribleMethod subscribleMethod = new SubscribleMethod(); subscribleMethod.setMethod(method); subscribleMethod.setSubscriber(object); // 指定订阅至 subscribleMethod.setThreadMode(threadMode); subscribleMethod.setType(types[0]); list.add(subscribleMethod); }else{ Log.d("lixm", "Parameter type error."); } } } clazz = clazz.getSuperclass(); } } } return list; } /** * 发送数据 * cacheMap中找到当前保存的所有订阅者 * 取出每一个订阅者的方法,循环调用执行 * @param paramObj */ public void post(Object paramObj) { // 直接循环cacheMap,找到相应的方法执行 if (cacheMap != null && cacheMap.size() > 0) { Set
set = cacheMap.keySet(); Iterator iterator = set.iterator(); // 订阅者的集合 Log.d("lixm", "post(),iterator = " + iterator); while (iterator.hasNext()) { Object object = iterator.next(); List
list = cacheMap.get(object); // 取出每一个订阅者的方法 if (list == null || list.size() == 0) { return; } for (SubscribleMethod subscribleMethod : list) { // 循环执行每一个方法 // 判断参数的类型是否一致,列表中保存的参数类型,和传进来的参数类型是否一致 if (subscribleMethod.getType().isAssignableFrom(paramObj.getClass())) { invok(subscribleMethod, object, paramObj); } } } } } /** * 方法的执行 * * @param subscribleMethod 要执行方法的封装 * @param object 观察者(拥有方法的那个类) * @param paramObj 要执行方法的参数(post数据的封装) */ private void invok(SubscribleMethod subscribleMethod, final Object object, final Object paramObj) { final Method method = subscribleMethod.getMethod(); try { // todo 这里需要判断方法在哪个线程执行? if (subscribleMethod.getThreadMode() == ThreadMode.MAIN) { // 主线程执行 String mainThreadName = Thread.currentThread().getName() + "-" + Thread.currentThread().getId(); Log.d("lixm", "run in main thread,threadName = " + mainThreadName); method.invoke(object, paramObj); } else if (subscribleMethod.getThreadMode() == ThreadMode.BACKGROUND) { // 在子线程中执行 new Thread() { public void run() { try { String subThradName = Thread.currentThread().getName() + "-" + Thread.currentThread().getId(); Log.d("lixm", "run in sub thread,subThradName = " + subThradName); method.invoke(object, paramObj); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }.start(); } } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } /** * 取消注册 * * @param object */ public void unRegister(Object object) { if (object != null) { if (cacheMap.containsKey(object)) { cacheMap.remove(object); } } }}

3、订阅者方法的封装类

import java.lang.reflect.Method;public class SubscribleMethod {    private Method method;          // 要执行的方法    private Object subscriber;      // 观察者(订阅者)    private ThreadMode threadMode;  // 指定方法要执行的线程    // 方法中的参数类型    private Class
type; public ThreadMode getThreadMode() { return threadMode; } public void setThreadMode(ThreadMode threadMode) { this.threadMode = threadMode; } public Object getSubscriber() { return subscriber; } public void setSubscriber(Object subscriber) { this.subscriber = subscriber; } public Class
getType() { return type; } public void setType(Class
type) { this.type = type; } public Method getMethod() { return method; } public void setMethod(Method method) { this.method = method; }}

4、自定义注解类

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.METHOD})   // 注解用到方法上的@Retention(RetentionPolicy.RUNTIME) // 运行时起作用public @interface Subscrible {    ThreadMode threadMode() default ThreadMode.MAIN;}

5、自定义参数类

public class EventBean {    private String one;    private String two;    public EventBean(String one , String two){        this.one = one;        this.two = two;    }    public String getOne() {        return one;    }    public void setOne(String one) {        this.one = one;    }    @Override    public String toString() {        return "EventBean{" +                "one='" + one + '\'' +                ", two='" + two + '\'' +                '}';    }}
public enum ThreadMode {    MAIN,    BACKGROUND}

转载地址:https://blog.csdn.net/dami_lixm/article/details/97493155 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:android通过USB读取身份证信息
下一篇:RxJava学习总结(一)

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年03月24日 22时41分51秒