Reutilización de objetos de mensaje (modo Flyweight en Android)

1. ¿Qué es el modelo Flyweight?

1. Introducción

El modo Flyweight, llamado FlyWeight, tiene como objetivo reutilizar objetos, evitar la duplicación y crear una gran cantidad de objetos, lo que ahorra el consumo de recursos del sistema.

Introducción al modo Flyweight: https://www.cnblogs.com/adamjwh/p/9070107.html

Práctica del modelo de peso mosca: https://www.jianshu.com/p/b925b8cb6494

En segundo lugar, la implementación en Message

Sabemos que Android es un mecanismo impulsado por eventos . Habrá una combinación de varios eventos para formar la visualización e interacción de la aplicación, y también involucra la comunicación entre hilos. Todos necesitamos usar Message para encapsular un objeto a través de Message. , Que describe el tipo, los parámetros y los controladores del evento . Se puede ver que con los eventos continuos o concurrentes, Message será creado y generado por una gran cantidad de objetos , y si una gran cantidad de objetos se crea frecuentemente, causará un consumo serio de memoria , activará GC con frecuencia , etc., y afectará el rendimiento de la aplicación, por lo que Utilice el modo Flyweight para reutilizar el objeto de mensaje, no es necesario crear un nuevo objeto cada vez .

1. Adquisición de objetos

Hay dos formas de obtener el objeto Message. Una es obtener un objeto nuevo directamente a través del método de construcción new, y la otra es obtener un objeto usando el método get. La recomendación oficial es usar obtener. Por qué, porque obtiene un objeto del pool de objetos. A través del mecanismo de reutilización para garantizar que no se generen una gran cantidad de objetos; y nuevos medios que se genera un nuevo objeto cada vez.

Veamos la realización de obtener:

/**
 * Return a new Message instance from the global pool. Allows us to
 * avoid allocating new objects in many cases.
 */
public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

Después de leer, probablemente haya tal lógica, si sPool no está vacío, entonces sPool se devuelve como un objeto de mensaje; de ​​lo contrario, se crea un nuevo objeto, entonces, ¿qué es este sPool? ¿Qué es m.next? ¿Qué son las banderas? ¿Qué pasa con sPoolSize?

Ok, con estas preguntas, vayamos a las variables globales de Mensaje para encontrar:

// sometimes we store linked lists of these things
/*package*/ Message next;


/** @hide */
public static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;

private static final int MAX_POOL_SIZE = 50;

Bien, vemos que tanto sPool como next son de tipo Mensaje. Piénsalo de nuevo, ¿es como una lista enlazada? Sí, en realidad mantiene una lista vinculada para almacenar estos objetos de mensaje reciclados y luego recuperarlos del encabezado de la lista vinculada cuando se utilizan.

imagen

La estructura general puede referirse a la figura anterior, sPool es similar a la función de un puntero, luego apunta al siguiente objeto de mensaje que se puede reutilizar, si no hay un objeto disponible, apunta a nulo. De manera similar, el valor inicial de sPool también apunta a una referencia nula.En este momento, no hay ningún objeto en la lista vinculada, es decir, ingresará el código anterior, return new Message();creará directamente un nuevo objeto y regresará.

También vemos que hay un campo sPoolSize y un campo MAX_POOL_SIZE, que son más fáciles de entender, uno que representa la longitud de la lista enlazada actual y otro que representa la longitud máxima. Entonces, después de obtener un objeto en el código anterior, size–.

Después de obtener el objeto, hay otra configuración de flags = 0. ¿Por qué? De hecho, es solo una marca. Alguien ya ha utilizado la marca de este objeto. Esta marca se utilizará más adelante y se evaluará si el objeto se está utilizando durante el reciclaje.

2. Conservación de objetos

Como vimos anteriormente, existe una lista vinculada que almacena y proporciona objetos de mensaje reutilizados ¿Cuándo se insertan estos objetos en la lista vinculada? En el modo Flyweight simple, después de haber creado un objeto, usamos el estado interno como clave y el objeto como valor, que se guarda en el mapa, pero aquí no se guarda cuando se crea el objeto.

OK, continúe verificando y encuentre la posición clave:recycle()

public void recycle() {
    if (isInUse()) {
        if (gCheckRecycle) {
            throw new IllegalStateException("This message cannot be recycled because it "
                    + "is still in use.");
        }
        return;
    }
    recycleUnchecked();
}

Como puede ver aquí, la marca que se acaba de mencionar se usa aquí. Primero, primero determinará si está disponible y se puede reciclar. Si no lo está, devuelva directamente o arroje una excepción, e ingrese al programa de reciclaje si se puede reciclar.

/**
 * Recycles a Message that may be in-use.
 * Used internally by the MessageQueue and Looper when disposing of queued Messages.
 */
void recycleUnchecked() {
    // Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
    flags = FLAG_IN_USE;
    //类似于reset,将各个变量状态重置
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;
    
    //插入到链表表头
    //链表长度限制为50
    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}

Este fragmento de código se puede dividir en dos partes. La primera parte restablece estos atributos. Después de todo, se reutiliza. Si no le da uno nuevo, tiene que dar uno vacío. No puede dárselo a un objeto con contenido, eso causaría un problema. La segunda parte es insertar en la lista vinculada. Puede ver que esta es la operación de insertar en el encabezado de la lista vinculada. Entregue el objeto de mensaje al que apunta el sPool actual al siguiente, luego apunte sPool al objeto actual, y finalmente size ++.

sPool apunta al encabezado de la lista enlazada actual, esta comprensión está bien.

Obtener imagen
Inserte la descripción de la imagen aquí
Reciclar
Inserte la descripción de la imagen aquí

¿Y cuándo se llama al método de reciclaje? ¿Cuándo se reciclará?
Mantenga presionada la tecla Ctrl en el método y encontró un montón de lugares para llamar al método, pero de hecho, solo prestamos atención a algunos lugares.

Message msg = mHandler.obtainMessage(MSG_DISABLE, state1, state2, animate);
        if (Looper.myLooper() == mHandler.getLooper()) {
            // If its the right looper execute immediately so hides can be handled quickly.
            mHandler.handleMessage(msg);
            msg.recycle();
        } else {
            msg.sendToTarget();
        }

Aquí puede ver que después de llamar al método handleMessage, se llama al método de reciclaje.

if (Looper.myLooper() == mMainLooper) {
            mCallback.executeMessage(msg);
            msg.recycle();
            return;
        }

Después de que se ejecuta la devolución de llamada, se llama al método de reciclaje.

3. Resumen

Message es la reutilización de Flyweight. La clase Message asume múltiples roles de Flyweight Abstraction, Flyweight Object y Flyweight Factory Class, pero en realidad es bastante fácil de entender: una lista vinculada se mantiene internamente para almacenar hasta 50 objetos. Cuando se usa obtener para obtener objetos , Saque un objeto del encabezado de la tabla o cree uno nuevo.Cuando el objeto se recicla, las propiedades del objeto se restablecen y se almacenan en la lista vinculada.

Supongo que te gusta

Origin blog.csdn.net/lizebin_bin/article/details/91381542
Recomendado
Clasificación