Directorio de artículos
1. Análisis del principio de realización de los eventos fijos de EventBus
1.1 Introducción y arquitectura de EventBus
Cuando se trata de EventBus, creo que la mayoría de los desarrolladores de Android lo han usado. Es un marco de bus de eventos de publicación / suscripción diseñado para Android basado en el patrón de observador. Separa el receptor y el remitente del evento y simplifica la comunicación entre los componentes. La operación de comunicación es muy simple de usar, y la implementación del código fuente es de solo mil o dos mil líneas, lo que también es muy adecuado para el aprendizaje.
EventBus utiliza internamente el mecanismo del controlador para lograr la comunicación entre subprocesos, por lo que no es necesario utilizar el mecanismo del controlador para cambiar datos entre subprocesos (tenga en cuenta que EventBus no puede lograr la comunicación entre procesos, porque el singleton de EventBus solo es válido en un proceso).
1.2 ¿Qué es el evento fijo de EventBus?
Los eventos fijos son una característica más distintiva de EventBus. ¿Qué son los eventos fijos? Para responder a esta pregunta, debemos comenzar con eventos ordinarios.
public class EventBusTestActivity extends AppCompatActivity {
private ActivityEventBusTestBinding bind;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bind=ActivityEventBusTestBinding.inflate(getLayoutInflater());
setContentView(bind.getRoot());
//注册总线
EventBus.getDefault().register(this);
bind.btnSendMsg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//发送数据
EventBus.getDefault().post(new MyMessage("普通消息"));
}
});
}
class MyMessage{
final String msg;
public MyMessage(String msg) {
this.msg = msg;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//取消总线注册
EventBus.getDefault().unregister(this);
}
}
En general, el ciclo completo del evento EventBus ordinario de una actividad es el siguiente:
注册到总线 -> 发送消息 ->销毁消息
Parece perfecto, pero ¿y si hay dos actividades? ActivityA envía un mensaje, ActivityB también quiere recibirlo, pero cuando ActivityA envía un mensaje, ActivityB no se ha creado, es muy vergonzoso, los eventos pegajosos son para resolver este problema.
El uso de eventos fijos se puede enviar antes de que se cree la actividad suscrita y se puede recibir después de que se complete la creación.
ActivityA创建,注册总线->点击按钮,发送事件->ActivityB创建,消费事件
1.3 Principio de implementación de eventos pegajosos
¿Como funciona? Primero, veamos la función de envío de eventos permanentes
private final Map<Class<?>, Object> stickyEvents;
...
EventBus(EventBusBuilder builder) {
...
stickyEvents = new ConcurrentHashMap<>();
...
}
...
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = isMainThread();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
Como puede ver, aquí solo está el evento fijo almacenado en un ConcurrentHashMap, y luego se llama a la publicación para enviar el mensaje, lo que puede garantizar la entrega normal del mensaje. Pero aquí no vemos cómo eventbus envía mensajes después de que se crea la actividad de destino. De hecho, el misterio está en la parte donde la actividad registra EventBus:
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
...
if (subscriberMethod.sticky) {
if (eventInheritance) {
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
// --> Strange corner case, which we don't take care of here.
postToSubscription(newSubscription, stickyEvent, isMainThread());
}
}
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
Después de leer este código, se estima que todos se dieron cuenta de repente de que al registrarse, cuando se detectaba un evento fijo (la ubicación de almacenamiento específica es el grupo de eventos fijo que se agregó cuando se lanzó el evento fijo), el mensaje se publicó directamente. El principio de por qué los eventos fijos se pueden publicar antes de que se cree la actividad y los mensajes se pueden recibir cuando se crean.
register->subscribe->checkPostStickyEventToSubscription->postToSubscription
1.4 Otras pequeñas preguntas sobre eventos pegajosos
También puede preguntar, cuando se envía el evento fijo, se ha creado la actividad objetivo, ¿qué sucederá? ¿Recibirás dos mensajes duplicados? La respuesta es obviamente no, porque una vez que se ha creado la actividad de destino, la función de registro ya no se ejecuta. Naturalmente, no pueden aparecer dos mensajes duplicados. Si escribe accidentalmente EventBus.getDefault (). Register (this) dos veces, No importa, porque EventBus no se registra repetidamente después de que se registra la clase.
Las conclusiones anteriores se pueden ver en el código fuente de EventBus.