Código-fonte - Análise do princípio de realização de eventos pegajosos EventBus

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.

Insira a descrição da imagem aqui

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.

Acho que você gosta

Origin blog.csdn.net/qq_23594799/article/details/108028917
Recomendado
Clasificación