Tres lados de la publicación de Tencent para Android: ¿Cómo cambiar entre hilos de mensajes enviados por EventBus?

I. Introducción

EventBus es un marco de suscripción / publicación de eventos basado en el modo de observador. EventBus se puede utilizar para lograr una comunicación de mensajes de bajo acoplamiento entre diferentes módulos.

EventBus se usa ampliamente en algunos proyectos de producción debido a su simplicidad y estabilidad.

Usualmente usamos EventBus para distribuir algunos mensajes a los suscriptores de mensajes. Además, también podemos usar EventBus para pasar mensajes a diferentes hilos para su ejecución y procesamiento. Esto también implica algunos problemas de cambio de subprocesos y problemas de grupo de subprocesos. En el proceso de uso, hay algunas opciones de configuración. En este momento, debemos elegir diferentes métodos de cambio de subprocesos de acuerdo con los diferentes escenarios comerciales.

Este artículo analiza cómo usar EventBus para cambiar hilos de mensajes según los diversos métodos de cambio de hilo de EventBus y la implementación interna.

Autor: Cheng Hong
Enlace de sombra de tinta : https: //juejin.im/post/6844903944561377293

2. Cambio de hilo de EventBus

2.1 Subproceso de conmutación EventBus

EventBus es un marco de publicación / suscripción de eventos basado en el patrón de observador. Utilice EventBus para realizar una comunicación de mensajes de acoplamiento bajo entre diferentes módulos.

Durante tantos años desde que nació EventBus, se puede ver en muchos proyectos de producción. Como se puede ver en el log de actualización, además de su pequeño tamaño, también es muy estable. No se ha actualizado en los últimos dos años. La última actualización fue solo porque es compatible con todas las JVM, por lo que su uso no es limitado a Android.

Se puede decir que es muy estable y lo suficientemente estable como para dar una sensación. Si tiene algún problema con EventBus, debe ser al revés.

El uso de EventBus es ciertamente familiar para los viejos controladores de Android Hay demasiados materiales relacionados, por lo que no los repetiré aquí.

En Android, el cambio de hilo es una operación muy común y necesaria. Además de suscribirse y enviar mensajes, EventBus también puede especificar el hilo que recibe y procesa mensajes.

En otras palabras, ya sea que post()esté en cualquier hilo, los mensajes de EventBus se pueden distribuir a su hilo especificado, suena como la sensación cuando el mensaje es bastante fácil.

Sin embargo, no importa cómo cambie, hay varias situaciones:

  • El subproceso de la interfaz de usuario se corta en subprocesos secundarios.
  • El hilo secundario corta el hilo de la interfaz de usuario.
  • El hilo secundario corta otros hilos secundarios.

Cuando usamos EventBus, el mensaje de registro se @Subscribepuede anotar para completar el evento de registro, @Subscribelos parámetros se threadModepueden especificar usando el hilo para recibir mensajes.

@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventTest(event:TestEvent){
  // 处理事件
}

threadMode Es una enumeración, con múltiples modos para elegir:

  1. PUBLICAR, el valor predeterminado que envía el hilo es el que recibe el hilo.
  2. PRINCIPAL, cambie al hilo principal para recibir eventos.
  3. MAIN_ORDERED, un nuevo atributo agregado en v3.1.1, también cambia al hilo principal para recibir eventos, pero es ligeramente diferente de MAIN, que se describirá en detalle más adelante.
  4. FONDO, para garantizar que los eventos se reciban en el subproceso secundario. Los detalles son que si el mensaje es enviado por el hilo principal, cambiará al hilo secundario para recibirlo, y si el evento en sí es enviado por el hilo secundario, el hilo que envió el mensaje del evento se usará directamente para procesar el mensaje.
  5. ASYNC asegura que los eventos se reciban en subprocesos secundarios, pero la diferencia con BACKGROUND es que no distingue si el subproceso de envío es un subproceso secundario, pero recibe eventos en un subproceso diferente cada vez.

El método de conmutación de subprocesos de EventBus está relacionado principalmente con el postToSubscription()método EventBus .

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);
  }
}

Se puede ver en el postToSubscription()proceso, configuramos el valor de threadMode fueron procesados.

La lógica de este código es muy simple, veamos los detalles de su ejecución.

2.2 Cambiar al hilo principal para recibir eventos

Para recibir mensajes en el hilo principal, debe configurar threadMode en MAIN.

case MAIN:
  if (isMainThread) {
    invokeSubscriber(subscription, event);
  } else {
    mainThreadPoster.enqueue(subscription, event);
  }

La lógica de esta sección es muy clara. Si se considera que el hilo principal es el hilo principal, el evento será procesado directamente. Si es el hilo no principal, el evento será manejado por mainThreadPoster.

mainThreadPosterCódigo de seguimiento , código lógico específico en la clase HandlerPoster, que implementa la interfaz Poster, que es un Handler ordinario, pero looper utiliza el hilo principal "Main Looper", puede distribuir el mensaje al hilo principal.

Para mejorar la eficiencia, EventBus también ha realizado algunas pequeñas optimizaciones aquí, de las que vale la pena aprender.

Para evitar sendMessage()mensajes frecuentes en el hilo principal , el enfoque de EventBus es procesar tantos eventos de mensajes como sea posible en un mensaje, por lo que se utiliza un bucle while para obtener continuamente mensajes de la cola de mensajes.

Al mismo tiempo, para evitar ocupar el hilo principal durante mucho tiempo, se reenviará en un intervalo de 10ms (maxMillisInsideHandleMessage = 10ms) sendMessage(), que se utiliza para renunciar a la derecha de ejecución del hilo principal y evitar que la interfaz de usuario se atasque. y ANR.

MAINAsegúrese de que el receptor del evento, en el hilo principal, debe tener en cuenta que, si el evento se envía en el hilo principal, se utiliza MAINdirectamente ejecutado. Para desarrollar Chengdu superior y configurable en EventBus v3.1.1 agrega MAIN_ORDERED, no distingue entre el hilo actual, pero todos usan mainThreadPosterpara tratar, que está obligado a volver a la distribución de noticias Handler.

Cuando el evento debe abordarse en el hilo principal, no se puede realizar una operación que requiere mucho tiempo, esto no es nada que decir, además de las opciones MAINo MAIN_ORDEREDdepende de los requisitos comerciales específicos.

2.3 Cambiar a ejecución de subprocesos

Si desea hacer novedades en el procesamiento de subprocesos, se puede configurar para threadMode BACKGROUNDO AYSNC, se pueden lograr, pero hay algunas diferencias.

Veamos a BACKGROUNDtravés de postToSubscription()usted puede ver la lógica, BACKGROUNDdistingue entre hilos de eventos actuales, si es el hilo principal, el hilo principal de este evento de distribución no directa y si el hilo principal se backgroundPosterutiliza para distribuir el evento.

case BACKGROUND:
	if (isMainThread) {
		backgroundPoster.enqueue(subscription, event);
	} else {
		invokeSubscriber(subscription, event);
	}
break;
复制代码

BackgroundPoster también implementa la interfaz Poster, que también mantiene una cola de mensajes PendingPostQueue implementada con una lista vinculada,

En algunos estándares de codificación se menciona que en lugar de crear subprocesos directamente, es necesario utilizar grupos de subprocesos . EventBus sigue esta especificación, en BackgroundPoster en EventBus sobre el uso del grupo de executorServicesubprocesos para ejecutar el objeto.

Para mejorar la eficiencia, EventBus también tiene algunos consejos para que aprendamos cuando trabajamos con BackgroundPoster.

[Error al cargar la imagen ... (image-eb9c15-1603110903841)]

Como puede ver, en BackgroundPoster, cuando se procesan eventos lanzados por el hilo principal, solo habrá un hilo al mismo tiempo, que se repetirá para obtener eventos de procesamiento de eventos de la cola.

Sincronizado para garantizar el bloqueo de sincronización mediante datos de cola seguros para subprocesos mientras se utilizan identificados volátiles executorRunningpara garantizar que los que se ven en diferentes subprocesos de ejecución sean visibles.

Dado que BACKGROUNDen el momento de procesar las tareas, solo se usa un hilo, pero EventBus ha usado el grupo de hilos, parece un desperdicio. Pero seguir comprendiendo ASYNCla realización, saber cómo hacer un uso completo del grupo de subprocesos.

Y threadMode descrito anteriormente, la mayoría corresponde a un Poster, mientras que ASYNCel Poster correspondiente es AsyncPoster, el cual no hizo ningún tratamiento especial, todos los eventos son de tiro libre del cerebro EventBus de executorServiceeste grupo de subprocesos para manejar, esto también asegura que el subproceso donde el evento ocurre y el hilo que recibe el evento debe ser diferente, y también asegura que el evento será procesado en el hilo secundario.

public void enqueue(Subscription subscription, Object event) {
	PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
	queue.enqueue(pendingPost);
	eventBus.getExecutorService().execute(this);
}

Aquí debe estar en comprensión BACKGROUNDy ASYNC, aunque se puede garantizar que recibirá tratamiento en caso de que el hilo secundario, pero la implementación interna es diferente.

BACKGROUNDAl mismo tiempo, solo se usa un subproceso hijo para obtener y procesar eventos de la cola de eventos en un bucle, es decir, la eficiencia de ejecución del evento anterior afectará la ejecución de eventos posteriores. Por ejemplo, distribuye un evento, utilizándolo BACKGROUNDfrente a la cola, hay una operación que consume mucho tiempo, y si distribuye este evento, debe esperar a que la cola frente al evento se procese antes de que puedan continuar. Entonces, si busca la eficiencia de la ejecución, puede usar los eventos que se ejecutarán de inmediato ASYNC.

¿Eso no es todo uso ASYNCbien? Por supuesto, este tipo de decisión de paquete no será buena. El análisis específico de cuestiones específicas ASYNCtambién tiene sus propios problemas.

ASYNCNingún cerebro enviará una misión al grupo de subprocesos ExecutorService, y este grupo de subprocesos, si no lo configura, se usa por defecto en el caso de los Ejecutores newCachedThreadPool()creados.

Aquí quiero hablar sobre los estándares de codificación. No se recomienda usar Executors para crear hilos directamente. Una de las razones de esto es la estrategia de rechazo del grupo de hilos . newCachedThreadPoolSe crearán nuevos hilos de forma infinita para realizar tareas, cuando haya demasiadas tareas (eventos) aparecerá OOM.

De hecho, este es el EventBus en uso ASYNC, el verdadero problema.

Pero de hecho, deja que el desarrollador lo configure por sí mismo. También es difícil configurar una estrategia de rechazo razonable del grupo de subprocesos. Al rechazar, algunas tareas se abandonarán inevitablemente, es decir, se abandonarán algunos eventos. Cualquier estrategia de abandono es En el uso de EventBus, muestra que hay un error lógico y el evento que se debe recibir no se puede recibir. Como puede ver, la cola ilimitada aquí no es apropiada, pero tampoco es apropiado ASYNCusarla. La única forma es usarla razonablemente y usarla solo cuando sea necesario y razonable.

Tres. Resumen

En este punto, básicamente se borra el cambio de hilo de EventBus cuando se distribuyen eventos. De hecho, muchos materiales han escrito que pueden cambiar de hilo, pero para algunos detalles de uso, la descripción no se borra. Solo use este artículo para poner EventBus el cambio de hilo habla directamente sobre la limpieza.

EventBus es también una palabra de alta frecuencia relativamente común en los currículums. Durante la entrevista, a menudo pregunto a los entrevistadores sobre cómo cambiar de hilo. Pero debido a su simplicidad y facilidad de uso, de hecho, muchas veces hemos pasado por alto sus detalles de implementación.

Eso es todo por hoy, para resumir:

1. EventBus puede configurar el hilo que recibe el evento a través de threadMode.

2. Tanto MAIN como MAIN_ORDERED recibirán eventos en el hilo principal, la diferencia radica en si se distinguen y si el hilo donde ocurre el evento es el hilo principal.

3. ANTECEDENTES Para garantizar que el subproceso se reciba en el subproceso secundario, pasará por el grupo de subprocesos y utilizará un bucle de subprocesos para procesar todos los eventos. Por lo tanto, el tiempo de ejecución del evento se verá afectado por la eficiencia del procesamiento de eventos frente a la cola de eventos.

4. ASYNC asegura que los eventos se reciban en el subproceso secundario. A diferencia de BACKGROUND, ASYNC enviará tareas al grupo de subprocesos cada vez y las ejecutará a través de la programación del grupo de subprocesos. Sin embargo, debido a que el grupo de subprocesos usa una cola ilimitada, conducirá a OOM cuando haya demasiados eventos ASYNC pendientes.

Supongo que te gusta

Origin blog.csdn.net/Androiddddd/article/details/109168788
Recomendado
Clasificación