Artigo Diretório
1. Análise do princípio de realização de eventos pegajosos EventBus
1.1 Introdução e arquitetura do EventBus
Por falar em EventBus, acredito que a maioria dos desenvolvedores Android o utilizou. É uma estrutura de barramento de evento de publicação / assinatura projetada para Android com base no padrão do observador. Ele separa o receptor e o remetente do evento e simplifica a comunicação entre os componentes. A operação de comunicação é muito simples de usar, e a implementação do código fonte é de apenas uma ou duas mil linhas, o que também é muito adequado para o aprendizado.
O EventBus usa internamente o mecanismo do manipulador para obter comunicação cross-thread, portanto, não precisamos usar o mecanismo do manipulador para alternar dados entre os threads (observe que o EventBus não pode alcançar comunicação entre processos porque o singleton do EventBus só é válido em um processo).
1.2 O que é evento pegajoso EventBus
Os eventos fixos são um recurso mais distinto no EventBus. O que são eventos fixos? Para responder a essa pergunta, devemos começar com eventos comuns.
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);
}
}
Em geral, o ciclo completo de evento EventBus comum de uma Activity é o seguinte:
注册到总线 -> 发送消息 ->销毁消息
Parece perfeito, mas e se houver duas atividades? ActivityA envia uma mensagem, e ActivityB também quer recebê-la, mas quando ActivityA envia uma mensagem, ActivityB não foi criada, é muito embaraçoso, eventos pegajosos são para resolver tais problemas.
O uso de eventos fixos pode ser enviado antes que a atividade inscrita seja criada e recebido após a conclusão da criação.
ActivityA创建,注册总线->点击按钮,发送事件->ActivityB创建,消费事件
1.3 Princípio de implementação de eventos fixos
Como funciona? Primeiro, vamos olhar para a função de envio de eventos fixos
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 você pode ver, aqui está apenas o evento persistente armazenado em um ConcurrentHashMap e, em seguida, o post é chamado para enviar a mensagem, o que pode garantir a entrega normal da mensagem. Mas aqui não vemos como o eventbus envia mensagens depois que a atividade de destino é criada. Na verdade, o mistério está na parte em que a atividade 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);
}
}
Depois de ler este código, estima-se que todos repentinamente perceberam que, ao se registrar, quando um evento persistente foi detectado (o local de armazenamento específico é o pool de eventos persistentes que foi adicionado quando o evento persistente foi lançado), a mensagem foi publicada diretamente. O princípio de por que eventos fixos podem ser postados antes que a atividade seja criada e as mensagens podem ser recebidas quando criadas.
register->subscribe->checkPostStickyEventToSubscription->postToSubscription
1.4 Outras pequenas questões sobre eventos fixos
Você também pode querer perguntar, quando o evento sticky for enviado, a atividade de destino foi criada, o que acontecerá? Você receberá duas mensagens duplicadas? A resposta é obviamente não, porque depois que a atividade de destino foi criada, a função de registro não é mais executada. Naturalmente, duas mensagens duplicadas não podem aparecer. Se você acidentalmente gravar EventBus.getDefault (). Register (this) duas vezes, Não importa, porque EventBus não se registra repetidamente depois que a classe é registrada.
As conclusões acima podem ser vistas no código-fonte do EventBus.