Réutilisation des objets de message (mode Flyweight sous Android)

1. Qu'est-ce que le modèle Flyweight

1. Introduction

Le mode Flyweight, à savoir FlyWeight, vise à réutiliser des objets, à éviter la duplication et à créer un grand nombre d'objets, économisant ainsi la consommation de ressources du système

Introduction au mode poids mouche: https://www.cnblogs.com/adamjwh/p/9070107.html

Pratique du modèle poids mouche: https://www.jianshu.com/p/b925b8cb6494

Deuxièmement, la mise en œuvre dans Message

Nous savons qu'Android est un mécanisme événementiel . Il y aura une combinaison de divers événements pour former l'affichage et l'interaction de l'application, et cela implique également la communication entre les threads. Nous devons tous utiliser Message pour encapsuler un objet via Message. , Qui décrit le type, les paramètres et les gestionnaires de l'événement . On peut voir qu'avec les événements continus ou simultanés, Message sera créé et généré par un grand nombre d'objets , et si un grand nombre d'objets est créé fréquemment, cela entraînera une consommation importante de mémoire , déclenchera fréquemment GC, etc., et affectera les performances de l'application, donc Utilisez le mode Flyweight pour réutiliser l'objet de message, il n'est pas nécessaire de créer un nouvel objet à chaque fois .

1. Acquisition d'objets

Il existe deux méthodes pour obtenir l'objet Message. L'une consiste à obtenir un nouvel objet directement via la méthode de construction new, et l'autre consiste à obtenir un objet à l'aide de la méthode get. La recommandation officielle est d'utiliser get. Pourquoi, car il obtient un objet du pool d'objets. Grâce au mécanisme de réutilisation pour garantir qu'un grand nombre d'objets ne sera pas généré; et nouveau signifie qu'un nouvel objet est généré à chaque fois.

Regardons la réalisation d'obtenir:

/**
 * 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();
}

Après lecture, il existe probablement une telle logique, si sPool n'est pas vide, alors sPool est renvoyé en tant qu'objet Message, sinon un nouvel objet est créé, alors qu'est-ce que ce sPool? Qu'est-ce que m.next? Que sont les drapeaux? Et sPoolSize?

Ok, avec ces questions, passons aux variables globales de Message pour trouver:

// 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;

OK, nous voyons que sPool et next sont de type Message. Pensez-y à nouveau, est-ce comme une liste chaînée? Oui, il gère en fait une liste liée pour stocker ces objets Message recyclés, puis les récupère à partir de la tête de la liste liée lors de son utilisation.

image

La structure générale peut faire référence à la figure ci-dessus, sPool est similaire au rôle d'un pointeur, next pointe vers l'objet de message suivant qui peut être réutilisé, s'il n'y a pas d'objet disponible, il pointe vers null. De même, la valeur initiale de sPool pointe également vers une référence nulle. À ce stade, il n'y a aucun objet dans la liste liée, c'est-à-dire qu'il entrera le code ci-dessus return new Message();et créera directement un nouvel objet et retournera.

Nous voyons également qu'il existe un champ sPoolSize et un champ MAX_POOL_SIZE, qui sont plus faciles à comprendre, l'un représentant la longueur de la liste chaînée courante, et l'autre représentant la longueur maximale. Donc, après avoir obtenu un objet dans le code ci-dessus, size–.

Après avoir récupéré l'objet, il y a un autre paramètre flags = 0. Pourquoi? En fait, c'est juste une marque. Le marquage de cet objet a déjà été utilisé par quelqu'un. Cette marque sera utilisée plus tard, et il sera jugé si l'objet est utilisé lors du recyclage.

2. Conservation des objets

Comme nous l'avons vu ci-dessus, il existe une telle liste liée qui stocke et fournit des objets de message réutilisés. Quand ces objets sont-ils insérés dans la liste liée? Dans le mode Flyweight simple, après avoir créé un objet, nous utilisons l'état interne comme clé et l'objet comme valeur, qui est enregistrée dans la carte, mais ici n'est pas enregistrée lorsque l'objet est créé?

OK, continuez à vérifier et trouvez la position clé:recycle()

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

Comme vous pouvez le voir ici, la marque qui vient d'être mentionnée est utilisée ici. Premièrement, elle déterminera d'abord si elle est disponible et peut être recyclée. Si ce n'est pas le cas, renvoyez directement ou lancez une exception et entrez dans le programme de recyclage si elle peut être recyclée.

/**
 * 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++;
        }
    }
}

Ce morceau de code peut être divisé en deux parties. La première partie réinitialise ces attributs. Après tout, il est réutilisé. Si vous n'en donnez pas un tout neuf, vous devez en donner un vide. Vous ne pouvez pas le donner à un objet avec du contenu. Il y aura alors un problème. La deuxième partie consiste à insérer dans la liste liée. Vous pouvez voir qu'il s'agit de l'opération d'insertion dans la tête de la liste liée. Donnez l'objet de message pointé par le sPool actuel à next, puis pointez sPool sur l'objet actuel, et enfin size ++.

sPool pointe vers la tête de la liste chaînée actuelle, cette compréhension est OK.

Obtenir une image
Insérez la description de l'image ici
Recycler
Insérez la description de l'image ici

Et quand la méthode de recyclage est-elle appelée? Quand sera-t-il recyclé?
Maintenez la touche Ctrl enfoncée sur la méthode et j'ai trouvé un tas d'endroits pour appeler la méthode, mais en fait, nous ne faisons attention qu'à quelques endroits.

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

Ici, vous pouvez voir qu'après l'appel de la méthode handleMessage, la méthode de recyclage est appelée.

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

Une fois le rappel exécuté, la méthode de recyclage est appelée.

3. Résumé

Message est la réutilisation de Flyweight. La classe Message assume plusieurs rôles de Flyweight Abstraction, Flyweight Object et Flyweight Factory Class, mais elle est en fait assez facile à comprendre: une liste liée est gérée en interne pour stocker jusqu'à 50 objets. Lorsque vous utilisez obtenir pour obtenir des objets , Sortez un objet de la tête du tableau ou créez-en un nouveau. Lorsque l'objet est recyclé, les propriétés de l'objet sont réinitialisées et stockées dans la liste chaînée.

Je suppose que tu aimes

Origine blog.csdn.net/lizebin_bin/article/details/91381542
conseillé
Classement