前言
发布线程发布事件之后 , 消息中心需要转发这些事件 , 并执行相应的订阅方法 ;
在转发的过程中 , 需要针对订阅方法的 @Subscribe 注解的不同 threadMode 属性进行不同的线程模式处理 ;
假如订阅方法的线程模式属性属性是 POSTING , 直接在发布线程中调用订阅方法 ;
假如订阅方法的线程模式属性属性是 MAIN , 则需要判定发布线程是否是主线程 ;
- 如果发布线程是主线程 , 则直接执行订阅方法 ;
- 如果发布线程不是主线程 , 则需要在主线程中执行订阅方法 ;
假如订阅方法的线程模式属性是 BACKGROUND , 则需要判定发布线程是否是主线程 ;
- 如果发布线程是主线程 , 则切换到子线程执行订阅方法 ;
- 如果发布线程不是主线程 , 则直接执行订阅方法 ;
可参考 【Android 异步操作】Android 线程切换 ( 判定当前线程是否是主线程 | 子线程中执行主线程方法 | 主线程中执行子线程方法 ) 博客的部分操作 ;
一、根据不同的线程模式进行不同的线程切换操作
首先 , 获取当前线程是否是主线程 : 参考 【Android 异步操作】Android 线程切换 ( 判定当前线程是否是主线程 | 子线程中执行主线程方法 | 主线程中执行子线程方法 ) 一、判定当前线程是否是主线程 博客章节 ;
boolean isMainThread = false;
if (Looper.getMainLooper() == Looper.myLooper()) {
isMainThread = true;
}
然后 , 获取订阅方法的线程模式 , 不同的线程模式进行不同的处理 ;
MyThreadMode threadMode = subscription.getSubscriberMethod().getThreadMode();
switch (threadMode) {
case POSTING:
break;
case MAIN:
break;
case MAIN_ORDERED:
break;
case BACKGROUND:
break;
case ASYNC:
break;
}
POSTING 线程模式下 , 不进行线程切换 , 直接调用反射方法执行订阅方法即可 ;
case POSTING:
invokeMethod(subscription, event);
break;
MAIN 线程模式下 , 需要判定发布线程是否是主线程 ;
- 如果发布线程是主线程 , 则直接执行订阅方法 ;
- 如果发布线程不是主线程 , 则需要在主线程中执行订阅方法 ;
为了方便 , 这里将 MAIN_ORDERED 与 MAIN 分支进行合并处理 ;
参考 【Android 异步操作】Android 线程切换 ( 判定当前线程是否是主线程 | 子线程中执行主线程方法 | 主线程中执行子线程方法 ) 二、子线程中执行主线程方法 博客章节 ;
case MAIN:
case MAIN_ORDERED:
if (isMainThread) {
invokeMethod(subscription, event);
} else {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
invokeMethod(subscription, event);
}
});
}
break;
BACKGROUND 线程模式下 , 判定发布线程是否是主线程 ;
- 如果发布线程是主线程 , 则切换到子线程执行订阅方法 ;
- 如果发布线程不是主线程 , 则直接执行订阅方法 ;
为了方便 , 这里将 ASYNC 与 BACKGROUND 分支进行合并处理 ;
参考 【Android 异步操作】Android 线程切换 ( 判定当前线程是否是主线程 | 子线程中执行主线程方法 | 主线程中执行子线程方法 ) 三、主线程中执行子线程方法 博客章节 ;
case BACKGROUND:
case ASYNC:
if (isMainThread) {
executorService.execute(new Runnable() {
@Override
public void run() {
invokeMethod(subscription, event);
}
});
} else {
invokeMethod(subscription, event);
}
break;
部分代码示例 :
private void postSingleSubscription(MySubscription subscription, Object event) {
boolean isMainThread = false;
if (Looper.getMainLooper() == Looper.myLooper()) {
isMainThread = true;
}
MyThreadMode threadMode = subscription.getSubscriberMethod().getThreadMode();
switch (threadMode) {
case POSTING:
invokeMethod(subscription, event);
break;
case MAIN:
case MAIN_ORDERED:
if (isMainThread) {
invokeMethod(subscription, event);
} else {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
invokeMethod(subscription, event);
}
});
}
break;
case BACKGROUND:
case ASYNC:
if (isMainThread) {
executorService.execute(new Runnable() {
@Override
public void run() {
invokeMethod(subscription, event);
}
});
} else {
invokeMethod(subscription, event);
}
break;
}
}
二、完整代码示例
package com.eventbus_demo.myeventbus;
import android.os.Handler;
import android.os.Looper;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyEventBus {
private static final Map<Class<?>, List<MySubscriberMethod>> METHOD_CACHE = new HashMap<>();
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, CopyOnWriteArrayList<MySubscription>> subscriptionsByEventType;
private final ExecutorService executorService;
private static MyEventBus instance;
private MyEventBus() {
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
executorService = Executors.newCachedThreadPool();
}
public static MyEventBus getInstance() {
if (instance == null) {
instance = new MyEventBus();
}
return instance;
}
public void register(Object subscriber) {
Class<?> clazz = subscriber.getClass();
List<MySubscriberMethod> subscriberMethods = findSubscriberMethods(clazz);
if (subscriberMethods != null && !subscriberMethods.isEmpty()) {
for (MySubscriberMethod method : subscriberMethods) {
subscribe(subscriber, method);
}
}
}
private void subscribe(Object subscriber, MySubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.getEventType();
CopyOnWriteArrayList<MySubscription> subscriptions =
subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
}
MySubscription subscription = new MySubscription(subscriber, subscriberMethod);
subscriptions.add(subscription);
List<Class<?>> eventTypes = typesBySubscriber.get(subscriber);
if (eventTypes == null) {
eventTypes = new ArrayList<>();
typesBySubscriber.put(subscriber, eventTypes);
}
eventTypes.add(eventType);
}
private List<MySubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<MySubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods == null) {
subscriberMethods = findByReflection(subscriberClass);
if (! subscriberMethods.isEmpty()) {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
}
} else {
return subscriberMethods;
}
return null;
}
private List<MySubscriberMethod> findByReflection(Class<?> subscriberClass) {
List<MySubscriberMethod> subscriberMethods = new ArrayList<>();
Method[] methods = subscriberClass.getMethods();
for (Method method : methods) {
int modifiers = method.getModifiers();
Class<?>[] params = method.getParameterTypes();
if (modifiers == Modifier.PUBLIC && params.length == 1) {
MySubscribe annotation = method.getAnnotation(MySubscribe.class);
if (annotation != null) {
MyThreadMode threadMode = annotation.threadMode();
MySubscriberMethod subscriberMethod = new MySubscriberMethod(
method,
threadMode,
params[0]
);
subscriberMethods.add(subscriberMethod);
}
}
}
return subscriberMethods;
}
public void post(Object event) {
Class<?> eventType = event.getClass();
CopyOnWriteArrayList<MySubscription> subscriptions =
subscriptionsByEventType.get(eventType);
if (subscriptions != null && subscriptions.size() > 0) {
for (MySubscription subscription : subscriptions) {
postSingleSubscription(subscription, event);
}
}
}
private void postSingleSubscription(MySubscription subscription, Object event) {
boolean isMainThread = false;
if (Looper.getMainLooper() == Looper.myLooper()) {
isMainThread = true;
}
MyThreadMode threadMode = subscription.getSubscriberMethod().getThreadMode();
switch (threadMode) {
case POSTING:
invokeMethod(subscription, event);
break;
case MAIN:
case MAIN_ORDERED:
if (isMainThread) {
invokeMethod(subscription, event);
} else {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
invokeMethod(subscription, event);
}
});
}
break;
case BACKGROUND:
case ASYNC:
if (isMainThread) {
executorService.execute(new Runnable() {
@Override
public void run() {
invokeMethod(subscription, event);
}
});
} else {
invokeMethod(subscription, event);
}
break;
}
}
private void invokeMethod(MySubscription subscription, Object event) {
try {
subscription.getSubscriberMethod().getMethod().invoke(
subscription.getSubscriber(),
event
);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
|