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

EventBus编程思想-实现简易版EventBus

蓬运诚
2023-12-01

这是编程思想系列的第二篇,这里挑选用的比较多的EventBus讲解一下,不纠结实现细节。先理解设计思想,这也是研究学习开源框架的第一步。
代码:点击GitHub
一个开源框架的出现肯定是有原因的,便捷,性能基本离不开这两点。而EventBus设计的初衷应该是为了便捷。回想自己为什么要使用EventBus就明白了。简单提两句

组件通信方式

Intent:使用它实现组件跳转,并且能携带参数,但只能携带少量数据,同时在跨组件通信时局限性比较大
Handler:使用Handler进行组件通信耦合严重,容易造成内存泄漏
Broadcast:使用广播进行组件通信效率不高,安全性不高
Interface:不能跨线程通信
aidl:使用成本高
看了上面这些,是不是就明白了为什么会有EventBus的原因了吧。
设计框架的过程像是做一个产品。你首先要想一下设计这个框架的目的是什么?需求在哪里?存在即合理,
抛开源码,我们先想一想?如果要做一个组件之间通信工具,如何设计?。既然是为了方便,那么我们想怎么使用它呢?想让它有什么功能。可能会想到下面三点,(也可能想不到,哈哈),能想到的都是好的产品经理。。。
(1)在任意地方,发射数据。
(2)在任意地方,接收数据。
(3)可以指定接收数据的线程。

这个过程,类似产品经理根据需求设计产品的过程。然后我们根据图纸去实现。给我们的产品取一个名字吧:EventBus,其实我更喜欢叫DataBus,名字而已。萝卜青菜,各有所爱。想法有了,如何实现呢?操作起来,是不是可以运用设计模式中的观察者模式。
观察者(订阅者):任意类下的任意方法
被观察者(被订阅者):数据(任意类发射的数据)

实现思路

通过注解形式,标记观察者,然后被观察者提供订阅方法,通过注解扫描,把所有的观察者注入到容器中。被观察者提供发射数据的方法,遍历容器找到接收数据的方法(通过参数类型区分),然后通过反射方式调用观察者的方法。这就实现了被观察者发射数据通知观察者的需求。

代码实现

定义注解:Subscribe

@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;
}

定义EventBus 的行为:IBus。其实就是约定用户如何使用

public interface IBus {

    /**
     * 订阅
     */
    void register(Object subscriber);

    /**
     * 取消订阅,防止内存泄露
     */
    void unRegister(Object subscriber);

    /**
     * 发射数据
     *
     * @param data
     */
    void send(Object data);
}

订阅者对象模型:SubscriptionMethod

public class SubscriptionMethod {
    private Method method;
    private Class<?> type;
    private ThreadMode threadMode;

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

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

    public void setType(Class<?> type) {
        this.type = type;
    }

    public ThreadMode getThreadMode() {
        return threadMode;
    }

    public void setThreadMode(ThreadMode threadMode) {
        this.threadMode = threadMode;
    }
}

线程模型枚举

public enum ThreadMode {
    POSTING,
    MAIN,
    BACKGROUND,
    ASYNC
}

被观察者:EventBus
mSubcription:保存观察者的容器
eventBusHelper 帮助类,做注解扫描,线程管理。 类的职责不能过重(遵循单一职责原则)

public class EventBus implements IBus {
/**
* 订阅方法
* key 订阅类
* value 类中的订阅方法集合
*/
private final Map<Object, List> mSubcription;
private final EventBusHelper eventBusHelper;

private EventBus() {
    eventBusHelper = new EventBusHelper();
    this.mSubcription = new HashMap<>();
}

private static class Instance {
    private static final EventBus instance = new EventBus();
}

public static EventBus getInstance() {
    return Instance.instance;
}

@Override
public void register(Object subscriber) {
    List<SubscriptionMethod> methodList = mSubcription.get(subscriber);
    if (methodList == null || methodList.size() == 0) {
        methodList = new ArrayList<>();
        Class<?> clazz = subscriber.getClass();
        while (clazz != null) {
            String className = clazz.getName();
            if (className.startsWith("java.") || className.startsWith("javax.") || className.startsWith("android.")) {
                break;
            }
            eventBusHelper.findAnnotationMethod(methodList, clazz);
            //查找父类,有继承关系
            clazz = clazz.getSuperclass();
        }
        mSubcription.put(subscriber, methodList);
    }
}

@Override
public void send(Object event) {
    if (mSubcription.size() == 0) {
        return;
    }
    Set<Object> set = mSubcription.keySet();
    Iterator<Object> iterable = set.iterator();
    while (iterable.hasNext()) {
        Object next = iterable.next();
        List<SubscriptionMethod> methodList = mSubcription.get(next);
        if (methodList == null) {
            continue;
        }
        int size = methodList.size();
        for (int i = 0; i < size; i++) {
            SubscriptionMethod method = methodList.get(i);
            //method.getType()是获取方法参数类型,这里是判断发布的对象类型是否与订阅方法的参数类型一致
            if (method.getType().isAssignableFrom(event.getClass())) {
                eventBusHelper.invokeWithThread(next, method, event);
            }
        }
    }
}

@Override
public void unRegister(Object target) {
    List<SubscriptionMethod> methodList = mSubcription.get(target);
    if (methodList == null) return;
    methodList.clear();
    mSubcription.remove(target);
}

}
帮助类:EventBusHelper,把注解扫描的代码抽离出来,避免被观察者EventBus职责过重,遵循单一职责的原则

class EventBusHelper {
    private final Handler mHandler;
    private final ExecutorService mExecutorService;

    public EventBusHelper() {
        this.mHandler = new Handler(Looper.getMainLooper());
        this.mExecutorService = Executors.newCachedThreadPool();
    }

    public void findAnnotationMethod(List<SubscriptionMethod> methodList, Class<?> clazz) {
        Method[] m = clazz.getDeclaredMethods();
        int size = m.length;
        for (int i = 0; i < size; i++) {
            Method method = m[i];
            Subscribe annotation = method.getAnnotation(Subscribe.class);
            if (annotation == null) {
                continue;
            }
            Type genericReturnType = method.getGenericReturnType();
            if (!"void".equals(genericReturnType.toString())) {
                throw new EventBusException("方法返回值必须是void");
            }
            int modifiers = method.getModifiers();
            if ((modifiers & Modifier.PUBLIC) != 1) {
                throw new EventBusException("方法修饰符必须是public,且是非静态,非抽象");
            }
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length != 1) {
                throw new EventBusException("方法参数个数必须是一个");
            }

            //这里就需要实例化订阅方法对象了
            SubscriptionMethod subscriptionMethod = new SubscriptionMethod();
            subscriptionMethod.setMethod(method);
            subscriptionMethod.setType(parameterTypes[0]);
            subscriptionMethod.setThreadMode(annotation.threadMode());
            methodList.add(subscriptionMethod);
        }
    }


    public void invokeWithThread(final Object next, final SubscriptionMethod method, final Object event) {
        //进行线程切换
        switch (method.getThreadMode()) {
            case POSTING:
                invoke(next, method, event);
                break;
            case MAIN:
                //通过Looper判断当前线程是否是主线程
                //也可以通过线程名判断 "main".equals(Thread.currentThread().getName())
                if (Looper.getMainLooper() == Looper.myLooper()) {
                    invoke(next, method, event);
                } else {
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            invoke(next, method, event);
                        }
                    });
                }
                break;
            case BACKGROUND:
                if (Looper.getMainLooper() == Looper.myLooper()) {
                    mExecutorService.execute(new Runnable() {
                        @Override
                        public void run() {
                            invoke(next, method, event);
                        }
                    });
                } else {
                    invoke(next, method, event);
                }
                break;
            case ASYNC:
                mExecutorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        invoke(next, method, event);
                    }
                });
                break;
        }
    }

    private void invoke(Object next, SubscriptionMethod method, Object event) {
        Method m = method.getMethod();
        try {
            m.invoke(next, event);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

大功告成,开始使用

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus.getInstance().register(this);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                EventBus.getInstance().send(new Message(1, "activity启动了"));
            }
        }).start();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void eventBus(Message message) {
        Log.i("event_bus", message.getMsg());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getInstance().unRegister(this);
    }
}

以上如果有理解不对,或者代码错误的地方,请大神在评论区留言,谢谢!

 类似资料: