这是编程思想系列的第二篇,这里挑选用的比较多的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);
}
}
以上如果有理解不对,或者代码错误的地方,请大神在评论区留言,谢谢!