Análisis del código fuente desde el punto de vista mecanismo controlador de mensajes

De hecho, Internet tiene un montón de muy buen artículo bien escrito, he querido escribir esto es para el pensamiento claro derrame cerebral y mejorar la memoria.

Aquí recomendar un excelente artículo:

https://blog.csdn.net/zip_tts/article/details/86097136#commentBox

mecanismo controlador de mensajes principalmente tiene cinco componentes, Handler, Looper, mensaje, MessageQueue, ThreadLocal

  • Controlador de mensajes medida que el centro de procesamiento para procesar los mensajes y enviar mensajes.
  • Looper como un mensaje de poder para adquirir el mensaje de distribución.
  • mensaje de este mensaje como un portador para llevar el mensaje.
  • MessageQueue como una cola de mensajes para almacenar mensajes.
  • ThreadLocal es un almacenamiento de datos de clase rosca interior, los datos se pueden obtener sólo en el hilo especificado.
    **

En primer lugar, ¿cuál es el mensaje

Por encima de todo, para entender lo que queremos la transmisión del mensaje es lo que hay dentro.

public final class Message implements Parcelable {
	public int what;
    public int arg1;
    public int arg2;
    public Object obj;
    public Messenger replyTo;
    int flags;
    long when;
    Bundle data;
    Handler target;
    }

Usted no se siente muy familiar? Todos tenemos que escribir un montón de métodos utilizados.
Aquí hay un objetivo, Handler es el tipo de lo que es para almacenar el mensaje del controlador de mensajes, lo que ayuda a comprender más tarde.

Dos, Handler y ejemplificación de envío

Ejemplos de controlador de constructor siete

public Handler() {
    this(null, false);
}

public Handler(Callback callback) {
    this(callback, false);
}

public Handler(Looper looper) {
    this(looper, null, false);
}

public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}
   
public Handler(boolean async) {
    this(null, async);
}

public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

Podemos ver en el código, en el que el hilo inferior Looper si no se especifica, se utiliza para crear una instancia Handler.
Sobre el envío de Handler, de hecho, hay muchos métodos, pero la mirada se pueden encontrar, los métodos finales se dirigen enqueueMessage, y son encapsula el mensaje Mensaje, y luego enviados.

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

El código anterior, el Mensaje de punto de destino a sí mismos, transmite al MessageQueue, bien entendido, los siguientes análisis MessageQueue enququqMessage ()

三, MessageQueue

booleano enqueueMessage (mensaje MSG, de largo cuando) {
si (msg.target == null) {
throw new IllegalArgumentException ( “Mensaje debe tener un objetivo.”);
}
Si (msg.isInUse ()) {
throw new IllegalStateException (msg + "Este mensaje ya está en uso.");
}

    synchronized (this) {
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

De hecho, la cola de mensajes, el mensaje de la hora almacenada en la lista enlazada, si el retraso no se establece de forma secuencial, no habría clasificados por hora.

Cuatro, Looper

El siguiente es el constructor Looper:

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

Se puede ver que es constructor es privado, es decir, Looper no es por el nuevo método para crear un objeto, entonces será sin duda otras formas de obtener. Continuar para ver el código fuente se encuentra dentro de ella hay prepareMainLooper, preparar método,

public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

Looper prepareMainLooper utiliza principalmente para crear el hilo principal, en circunstancias normales, está prohibido, ya que siempre existe la principal looper hilo. Y se puede ver, la principal forma de crear o preparar ().

 private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

Ahí es donde el ThreadLocal

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

Obviamente, esto crea el hilo inferior, y para mantener en un ThreadLocal.
Así que ahora Looper se ha creado la manera de utilizar, lo envía al Mensaje MessageQueue? de ese bucle ()

 public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        // This must be in a local variable, in case a UI event sets the logger
        final Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }


        try {
            msg.target.dispatchMessage(msg);
            end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
    }

He eliminado un cierto código, casi por encima del código del núcleo. MessageQueue esencialmente en una lista única, en bucle se utiliza para (;;), es un bucle infinito, detener el mensaje MessageQueue conseguir a través de al lado, si está vacío directamente retorno, bien mediante msg.target.dispatchMessage(msg)el envío de la información al controlador msg.target DispatchMessage tipo de movimiento.

Cinco, la adquisición y el procesamiento manejador

Luego vino el código al controlador de DispatchMessage () en

 public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

Éstos son algunos comunicado juicio. En Handler, declarar una interfaz de devolución de llamada, sólo hay una manera handleMessage, este enfoque es tratar con el Mensaje de, devolución de llamada pasa en el constructor. Por supuesto, si no hay devolución de llamada entrante en el constructor, si hay una manera, Handler también define un método handleMessage, el valor predeterminado es la aplicación vacía. Puede ser procesado por la anulación del mensaje de este método.
Así que todo este proceso llegó a su fin.

Publicado 57 artículos originales · ganado elogios 3 · Vistas 6220

Supongo que te gusta

Origin blog.csdn.net/qq_39830579/article/details/88738717
Recomendado
Clasificación