Optimización del uso de Android EventBus

  El artículo anterior Comprensión del uso de Android EventBus Finalmente, sospeché que el método de suscripción de búsqueda de reflexión afectaría la eficiencia, y vi en el sitio web oficial que se recomienda utilizar el índice de suscriptores en los productos de la aplicación. La razón dada es para ser más rápido y evitar accidentes.
  Utilice el índice de suscriptores para evitar costosas búsquedas de métodos de suscripción en tiempo de ejecución mediante la reflexión. Utiliza procesadores de anotaciones para buscar métodos de suscripción en tiempo de compilación.
  ¡Es realmente increíble! La sobrecarga en tiempo de ejecución se realiza en tiempo de compilación.

cumplir con los requisitos

  • El método de suscripción y la clase de suscriptor deben ser públicos.
  • La clase del evento debe ser pública.
  • El método de suscripción no se puede colocar en una clase anónima.

cómo generar índice

  Si es lenguaje Java, utilice el procesador de anotaciones. Si usa Kotlin, use Kapt.
  Aquí hablamos principalmente sobre el método de configuración usando Java. Dado que mi build.gradle.kts es un script de Kotlin, publicaré mi configuración.

android {
    
        
    defaultConfig {
    
        
        javaCompileOptions {
    
    
            annotationProcessorOptions.arguments["eventBusIndex"] = "com.example.testeventbus.MyEventBusIndex"
        }
    }    
}
dependencies {
    
    
    val eventbus_version = "3.3.1"
    implementation("org.greenrobot:eventbus:$eventbus_version")
    annotationProcessor("org.greenrobot:eventbus-annotation-processor:$eventbus_version")   
}         

cómo usar el índice

  Primero necesitas construir el proyecto. Como lo configuré, generará automáticamente la clase com.example.testeventbus.MyEventBusIndex.
  Cuando se inicializa el código, antes de llamar a EventBus.getDefault(), debe llamar a EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus().
  Eso es todo, no es necesario hacer nada más.

Combina el código para analizar el índice.

Analicémoslo basándonos en el ejemplo de uso y comprensión de Android EventBus   del artículo anterior .
  Es principalmente para analizar la lógica del método de suscripción de consultas actual.

clase agregada

  La clase generada automáticamente usando anotaciones es com.example.testeventbus.MyEventBusIndex, eche un vistazo a su implementación:

public class MyEventBusIndex implements SubscriberInfoIndex {
    
    
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;

    static {
    
    
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();

        putIndex(new SimpleSubscriberInfo(MainActivity.class, true, new SubscriberMethodInfo[] {
    
    
            new SubscriberMethodInfo("onMessageEvent", MessageEvent.class, ThreadMode.MAIN),
            new SubscriberMethodInfo("onMessage", MessageEvent.class, ThreadMode.MAIN),
        }));

    }

    private static void putIndex(SubscriberInfo info) {
    
    
        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
    }

    @Override
    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
    
    
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
    
    
            return info;
        } else {
    
    
            return null;
        }
    }
}

  Esta clase hereda SubscriberInfoIndex e implementa el método getSubscriberInfo (Class <?> subscriberClass). Al mismo tiempo, podemos ver que en el bloque de código estático de la clase MyEventBusIndex, la información relevante del método de suscripción se coloca en el miembro estático SUBSCRIBER_INDEX. .
  En este ejemplo, la clave de SUBSCRIBER_INDEX es MainActivity.class y MainActivity es el objeto del suscriptor. SUBSCRIBER_INDEX en realidad usa la clase del objeto de suscriptor como clave y el valor es la clase de implementación de SubscriberInfo. Aquí, su valor es un objeto de clase SimpleSubscriberInfo.
  El tercer parámetro inicializado por SimpleSubscriberInfo es una matriz de SubscriberMethodInfo, y SubscriberMethodInfo se utiliza para describir el método de suscripción. En el ejemplo, declaramos dos métodos, por lo que habrá dos matrices. En la comprensión del uso de Android EventBus, encontramos estos dos métodos a través de la reflexión. Ahora hemos encontrado estos dos métodos directamente. Esto es lo que significa buscar en tiempo de ejecución y buscar en tiempo de compilación en el sitio web oficial.

Coloque el índice generado en EventBus.getDefault()

  Debido a que implementamos operaciones relacionadas a través de EventBus.getDefault() cada vez que llamamos, debemos colocar el índice generado en EventBus.getDefault() para que funcione. Se realiza a través de EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus().
  Primer vistazo a EventBus.builder().addIndex(new MyEventBusIndex())

    /** Adds an index generated by EventBus' annotation preprocessor. */
    public EventBusBuilder addIndex(SubscriberInfoIndex index) {
    
    
        if (subscriberInfoIndexes == null) {
    
    
            subscriberInfoIndexes = new ArrayList<>();
        }
        subscriberInfoIndexes.add(index);
        return this;
    }

  Se puede ver que el MyEventBusIndex recién generado se agrega a la variable miembro subscriberInfoIndexes. subscriberInfoIndexes es de tipo ArrayList.
  Mire nuevamente el método installDefaultEventBus():

    /**
     * Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be
     * done only once before the first usage of the default EventBus.
     *
     * @throws EventBusException if there's already a default EventBus instance in place
     */
    public EventBus installDefaultEventBus() {
    
    
        synchronized (EventBus.class) {
    
    
            if (EventBus.defaultInstance != null) {
    
    
                throw new EventBusException("Default instance already exists." +
                        " It may be only set once before it's used the first time to ensure consistent behavior.");
            }
            EventBus.defaultInstance = build();
            return EventBus.defaultInstance;
        }
    }

    /** Builds an EventBus based on the current configuration. */
    public EventBus build() {
    
    
        return new EventBus(this);
    }    

  Genere EventBus.defaultInstance directamente en build(). Llame a EventBus.getDefault() más tarde para obtener EventBus.defaultInstance.
  EventBus inicializa el código sobre el índice:

    EventBus(EventBusBuilder builder) {
    
    
        logger = builder.getLogger();
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadSupport = builder.getMainThreadSupport();
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
        backgroundPoster = new BackgroundPoster(this);
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        eventInheritance = builder.eventInheritance;
        executorService = builder.executorService;
    }

  Lo principal son las dos oraciones del medio sobre indexCount y subscriberMethodFinder. Establezca la colección Index en el objeto de clase SubscriberMethodFinder suscriptorMethodFinder. Sabemos que SubscriberMethodFinder trata de encontrar métodos de suscripción. Al realizar la búsqueda, está relacionado con subscriberInfoIndexes. Cuando el índice no se establece antes, está vacío y se omite. Ahora que se ha establecido el valor, es hora de revisar la lógica para encontrar el método de suscripción.

Encuentra una manera de suscribirte

  No tenemos que comenzar desde el principio, simplemente salte al código relevante, simplemente busqueUsingInfo(Class<?> subscriberClass) en la clase subscriberMethodFindermétodo:

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    
    
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
    
    
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {
    
    
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
    
    
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
    
    
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
    
    
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

  El cambio clave es getSubscriberInfo(findState). El findState.subscriberInfo devuelto por esta pieza estaba vacío antes, por lo que se usará findUsingReflectionInSingleClass(findState). Ahora devuelve no vacío, por lo que no es necesario usar el método de búsqueda de reflexión.
  Ahora eche un vistazo a getSubscriberInfo(findState):

    private SubscriberInfo getSubscriberInfo(FindState findState) {
    
    
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
    
    
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
    
    
                return superclassInfo;
            }
        }
        if (subscriberInfoIndexes != null) {
    
    
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
    
    
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
    
    
                    return info;
                }
            }
        }
        return null;
    }

  En este momento, findState.subscriberInfo es nulo, pero subscriberInfoIndexes ya no es nulo porque le asignamos un valor. Para nuestro ejemplo, hay un objeto MyEventBusIndex en subscriberInfoIndexes. Luego llame a su método getSubscriberInfo(Class<?> subscriberClass). Devuelve un objeto SimpleSubscriberInfo. Luego se devuelve el objeto.
  Regrese al método findUsingInfo() y luego llame a getSubscriberMethods() de SimpleSubscriberInfo. como sigue:

    @Override
    public synchronized SubscriberMethod[] getSubscriberMethods() {
    
    
        int length = methodInfos.length;
        SubscriberMethod[] methods = new SubscriberMethod[length];
        for (int i = 0; i < length; i++) {
    
    
            SubscriberMethodInfo info = methodInfos[i];
            methods[i] = createSubscriberMethod(info.methodName, info.eventType, info.threadMode,
                    info.priority, info.sticky);
        }
        return methods;
    }

  Ahora hay 2 SubscriberMethodInfo en SimpleSubscriberInfo, y ahora es necesario convertir SubscriberMethodInfo en SubscriberMethod, lo cual se logra llamando a createSubscriberMethod ().

    protected SubscriberMethod createSubscriberMethod(String methodName, Class<?> eventType, ThreadMode threadMode,
                                                      int priority, boolean sticky) {
    
    
        try {
    
    
            Method method = subscriberClass.getDeclaredMethod(methodName, eventType);
            return new SubscriberMethod(method, eventType, threadMode, priority, sticky);
        } catch (NoSuchMethodException e) {
    
    
            throw new EventBusException("Could not find subscriber method in " + subscriberClass +
                    ". Maybe a missing ProGuard rule?", e);
        }
    }

  SubscriberClass es la clase del objeto de clase de suscriptor, aquí el método correspondiente se obtiene a través de getDeclaredMethod (), para que se pueda generar el objeto SubscriberMethod.
  De esta manera, regrese al método findUsingInfo () y comience a juzgar si el método de suscripción se puede agregar al conjunto de resultados a través de findState.checkAdd () nuevamente. Esta lógica de juicio se encuentra en el artículo anterior Comprensión del uso de Android EventBus.
  Ahora comprende cómo Index puede reemplazar el método de buscar suscripciones mediante la reflexión.

Supongo que te gusta

Origin blog.csdn.net/q1165328963/article/details/132240392
Recomendado
Clasificación