Mecanismo del controlador de Android Ver manual

El segundo mecanismo Handler

Si me pregunta cuál es el mayor progreso en el siglo XXI, creo que es una vida conveniente. A través de teléfonos móviles, podemos hacer pedidos directamente de los productos que queremos comprar, y luego esperar a que el hermano del mensajero los entregue. nuestra puerta. Solo tenemos que firmar para recibir. Olla arrocera Deshagámonos de la leña en los viejos tiempos, y podemos recordarle cuando el arroz está cocido sin necesidad de que otros lo cuiden. Cuando termine el trabajo en mano, puedes disfrutar del arroz fragante directamente. Con todo, eliminamos todo tipo de cosas que una persona necesita hacer, excepto las cosas que debe hacer usted mismo, como comer y dormir, puede dejar que otros o algunos electrodomésticos lo hagan.
Para que sepas que el arroz está listo y que el servicio de mensajería ha sido entregado, debes ser notificado a través de algún tipo de evento. El controlador juega un papel importante en el hilo de Android, porque no puedes entregar el servicio de mensajería mientras prendes fuego. en casa Cocinar, por lo que asigna todas estas tareas a otras personas. Estas personas tienen múltiples subprocesos, entonces, ¿cómo sabe el progreso de su trabajo o los resultados del trabajo? Por ejemplo, ¿cuánto tiempo tardará en cocinarse el arroz y dónde se ha entregado el servicio de mensajería? La solución de Google te permite asignar un administrador (Handler) a estos hilos, a través del cual puedes entender su situación cuando lo necesites sin estar siempre atento.

descripción general

Si todo el proceso de aplicación de Android es una empresa, cada subproceso representa un departamento u otro puesto, y el subproceso principal es el presidente de la empresa (CEO), podemos llamarlo Sr. U (el subproceso principal también se denomina subproceso de interfaz de usuario), y U El gerente general es naturalmente responsable de algunas tareas importantes, incluidas algunas decisiones comerciales muy importantes, que son relativamente intuitivas y generalmente requieren decisiones rápidas. (El subproceso principal controla la visualización de la interfaz de la interfaz de usuario y no puede realizar operaciones que consumen mucho tiempo). U siempre está ocupado con los asuntos, por lo que no hace todo, por lo que comienza a reclutar personas (creando hilos). Primero recluta a una secretaria para que trabaje con él (en este momento, el looper vinculado al controlador es el looper donde el el hilo principal está ubicado), y luego recluté a algunos programadores para ayudarme a trabajar (hilos). Aunque U siempre está ocupado, a menudo le pido a mi secretaria que haga un seguimiento del progreso. En WeChat, la secretaria desliza el WeChat, y una vez recibe los resultados (cola de mensajes de MessageQueue) registrados en el mensaje del programador, enviará secuencialmente el nombre del proyecto recibido (msg.what) y el progreso del proyecto (msg. obj) le dijo al Sr. U que una vez que se complete el proyecto, el Sr. Puede tomar los resultados del proyecto para negociar con el cliente si no tiene nada más que hacer (visualización de la interfaz).
Deje que el subproceso principal no realice estas operaciones que consumen mucho tiempo y dígale al subproceso principal el resultado final en el subproceso, que es el objetivo principal de Handler . Si cree que existe una necesidad de comunicación entre subprocesos, puede implementarla a través del controlador. Ya sea entre el subproceso principal y el subproceso, o entre el subproceso y el subproceso, puede comunicarse a través de el manejador Pero un controlador solo puede estar vinculado a un hilo, al igual que la secretaria mencionada anteriormente solo sirve al presidente U, porque también debe dividir las áreas comerciales para otros, al igual que los gerentes de diferentes departamentos, pueden intercambiar datos comerciales y cooperación, pero en realidad pertenecen a diferentes áreas de trabajo.

tabla de roles

Role identidad real efecto Observación
U 总 El subproceso principal generalmente también se denomina subproceso de interfaz de usuario. Principalmente maneja algunos eventos de interfaz de usuario y es responsable de recibir mensajes de difusión. Al mismo tiempo, también puede crear subprocesos para manejar otras tareas. Si el subproceso principal maneja tareas que consumen mucho tiempo, cuando el usuario no procesa la interacción de la interfaz de usuario. después de más de 5 segundos, se activará ANR. Hilo principal que inicia la aplicación automáticamente
programador Subproceso subproceso secundario Principalmente responsable de procesar algunos trabajos que consumen mucho tiempo, como solicitudes de red, lectura y escritura de archivos. Subprocesos iniciados manualmente
pequeño secreto controlador controlador Responsable de la entrega de mensajes entre subprocesos, capaz de pasar mensajes a la cola de mensajes MessageQueue
para procesar mensajes enviados a través de Looper
Un hilo puede tener varios controladores
informe de trabajo del secretario Circulador de bucle Bucle los mensajes de la cola de mensajes vinculados al hilo principal Al mismo tiempo, un hilo tiene solo un looper.
WeChat de Xiao Mi Cola de mensajes MessageQueue Responsable de almacenar los mensajes enviados por cada hilo. -
La secretaria recibió un mensaje de WeChat. mensaje mensaje La unidad de datos de comunicación entre subprocesos, que almacena el contenido que se va a comunicar. -

Diagrama de lógica de negocios del controlador de subproceso principal

Combinado con la descripción en la descripción general, describiré el trabajo principal del controlador en el hilo principal de la siguiente manera.
inserte la descripción de la imagen aquí

De acuerdo con este diagrama de flujo, podemos dividir el trabajo principal en los siguientes pasos:
1. Preparación antes de la comunicación de subprocesos asincrónicos
Este paso crea principalmente objetos Looper (procesadores), objetos Handler y objetos MessageQueue (colas de mensajes) en el subproceso principal, y Estos son todos los objetos principales relacionados con el hilo.
2. El bucle de mensajes y
el subproceso de envío de mensajes envían el objeto del mensaje a MessageQueue vinculado al subproceso principal a través del controlador. Al mismo tiempo, el Looper ciclará continuamente la cola de mensajes. Una vez que el mensaje se extrae de ella. , se enviará al procesador que creó el mensaje (Handler), el controlador realiza las operaciones de procesamiento correspondientes en el método handleMessage
3. Procesamiento de mensajes
El controlador realiza las operaciones de procesamiento correspondientes en el método handleMessage Si el controlador se crea en el subproceso principal, puede realizar operaciones de interfaz de usuario.

Diagrama lógico del controlador de subprocesos

El procesamiento del controlador puede pasar mensajes en subprocesos al subproceso principal, y los subprocesos también pueden comunicarse entre sí a través del controlador, como se muestra en la siguiente figura:
inserte la descripción de la imagen aquí

De la figura anterior, debemos prestar atención a las siguientes relaciones:

  • 1 hilo (Thread) solo se puede vincular a 1 looper (Looper), pero puede tener varios controladores (Handler)
  • Un circulador (Looper) se puede vincular a varios manipuladores (Manejador), y estos Manipuladores pueden ser de diferentes subprocesos
  • 1 controlador (Handler) solo se puede vincular a 1 looper (Looper)
  • El MessageQueue que el Manejador envía el mensaje depende del Looper que estaba enlazado cuando se creó.

Sugerencias: los controladores de subprocesos múltiples pueden enviar mensajes a un MessageQueue mantenido por un Looper, pero el controlador que Looper quiere distribuir mensajes es el que envió originalmente el mensaje, es decir, el mensaje enviado por sí mismo es procesado por sí mismo al final. La razón se puede ver debajo de los consejos.

Usos del controlador

Revisemos brevemente cómo se puede usar un controlador:
1. Crear controlador y procesamiento de mensajes
Al heredar el controlador y anular el método handleMessage, se puede realizar el procesamiento después de la recepción del mensaje.
El alcance de la instancia del controlador creado en él debe incluir el hilo que necesita enviar el mensaje, de lo contrario no es válido para el envío de mensajes.

    private  Handler handler=new Handler(){
    
    
        @Override
        public void handleMessage(Message msg) {
    
    
           super.handleMessage(msg);// 需执行的操作

        }
    };

2. Enviar un mensaje desde el hilo

      Message message=handler.obtainMessage();
      message.what=100;
      message.arg1=i;
      message.obj="消息内容";
      handler.sendMessage(message);

donde el objeto Mensaje

Nombre del Atributo tipo efecto
mensaje.qué tipo int Se puede utilizar para identificar el tipo de mensaje enviado.
mensaje.arg tipo int Se puede usar para transmitir contenido de mensajes de tipo int, se pueden asignar arg1 y arg2, y el espacio ocupado será más pequeño que el de obj
mensaje.obj Tipo de objeto Se puede usar para pasar varios tipos de contenido de mensajes

3. Usar la publicación para enviar y procesar mensajes
Además del método sendMessage, también podemos enviar mensajes a través de la distribución posterior, pero el método de publicación encapsula el corredor en Messgae para enviar y procesar inmediatamente, y el principio de funcionamiento es similar.

    mHandler.post(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                ... // 需执行的操作 
            }
    });

consejos

1. ¿Cómo juzga Looper qué controlador maneja el mensaje?
Ingrese el código fuente interno de mHandler.sendMessage(msg) a través de la ruta a continuación, podemos encontrar que cuando enviamos un mensaje, Message.target se pasa como una referencia a sí mismo como un atributo, y Looper pasará este destino al especificado Controlador al realizar un bucle en el mensaje Mensaje para la distribución de mensajes.

方法路径:
sendMessage(msg)
– sendMessageDelayed(Mensaje msg, long delayMillis)
 — sendMessageAtTime(Mensaje msg, long uptimeMillis)
   ---- enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    
    
                 // 1. 将msg.target赋值为this
                 // 把当前的Handler实例对象作为msg的target属性
                 msg.target = this;
                 // Looper的loop()在消息循环时,会从消息队列中取出每个消息msg,然后执行msg.target.dispatchMessage(msg)去处理消息
                 // 实际上则是将该消息派发给对应的Handler实例        

                // 2. 调用消息队列的enqueueMessage()
                // 即:Handler发送的消息,最终是保存到消息队列
                return queue.enqueueMessage(msg, uptimeMillis);
 }

2. Pérdida de memoria del controlador

Cuando un objeto ya no se usa y debe reciclarse, otro objeto en uso tiene una referencia a él, lo que hace que el objeto ya no se recicle. Esto hace que los objetos que deberían haberse reciclado permanezcan en la memoria del montón, lo que provoca una fuga de memoria.

Razón de la fuga
Cuando el mensaje existe en MessageQueue y no se ha liberado (mensaje sin procesar/cuando el mensaje se está procesando), significa que hay una instancia del controlador retenida por el mensaje. en el primer punto de conocimiento se colocará el controlador actual. El objeto de instancia se puede conocer como el atributo de destino de msg.
Dado que Handler = clase interna no estática/clase interna anónima (2 formas de uso), contiene la referencia de la clase externa (es decir, la instancia de la actividad) de forma predeterminada. Una vez que la actividad está a punto de reciclarse, la instancia del controlador permanece en la memoria del montón Por lo tanto, la actividad no se puede reciclar, lo que conduce a pérdidas de memoria.
inserte la descripción de la imagen aquí

Solución
1. Utilice una clase interna estática
Principio: la clase interna estática no contiene una referencia a la clase externa de forma predeterminada, por lo que la relación de referencia de "mensaje sin procesar/en proceso -> Instancia del controlador -> clase externa" no existe.
Solución específica: establezca la subclase de Handler como una clase interna estática. Además, WeakReference también se puede usar para mantener clases externas para garantizar que las clases externas se puedan reciclar. Porque: los objetos con referencias débiles tienen un ciclo de vida corto. Cuando el subproceso del recolector de elementos no utilizados escanea, una vez que se encuentra un objeto con una referencia débil, su memoria se recuperará independientemente de si el espacio de memoria actual es suficiente o no.
Código de resolución:

    // 设置为:静态内部类
    private static class SHandler extends Handler{
    
    

        // 定义 弱引用实例
        private WeakReference<Activity> reference;

        // 在构造方法中传入需持有的Activity实例
        public SHandler(Activity activity) {
    
    
        // 使用WeakReference弱引用持有Activity实例
         reference = new WeakReference<Activity>(activity); }

        @Override
        public void handleMessage(Message msg) {
    
    
        
        }
    }

2. Utilice el ciclo de vida de la clase externa para borrar la cola de mensajes en el controlador.
El principio: no solo hace que la relación de referencia de "mensaje sin procesar/procesando -> instancia del controlador -> clase externa" ya no exista, sino que también hace que el ciclo de vida del Manejador (Es decir, el período en que existe el mensaje) Sincronizar con el ciclo de vida de la clase externa
Esquema específico: Cuando la clase externa (aquí, Actividad se toma como ejemplo) finaliza el ciclo de vida (el sistema llamará a onDestroy() en este momento), borre todos los mensajes en la cola de mensajes del controlador ( Call removeCallbacksAndMessages(null))
para resolver el código:

@Override
    protected void onDestroy() {
    
    
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
        // 外部类Activity生命周期结束时,同时清空消息队列 & 结束Handler生命周期
    }

3. Cambie rápidamente al esquema de ejecución del subproceso principal
1. Cambie creando un Looper Handler vinculado al subproceso principal

    new Handler(Looper.getMainLooper()).post(new Runnable() {
    
    
        @Override
        public void run() {
    
    
            //此时已在主线程中
        }
    });

2, método activity.runOnUiThread (acción ejecutable)

public void updateOnUI(Activity activity) {
    
    
        activity.runOnUiThread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                //此时已在主线程中
            }
        });
    }

3, view.post (acción ejecutable)

public void updateOnUI(View view) {
    
    
        	view.post(new Runnable() {
    
    
        	@Override
      		public void run() {
    
    
      	      //此时已在主线程中
      	    }
    	});
	}

Posibles problemas relacionados

1. ¿Cuál es la diferencia entre handler.sendMessage() y handler.post()?
Mirando el código fuente de Handler, se puede encontrar que el método final enviado a MessageQueue es enqueueMessage() en Handler, pero para el procesamiento de Message, el resultado del mensaje se devolverá a su devolución de llamada cuando se distribuya.
2. ¿Cuántos Handlers puede tener un hilo? ¿Cuántos loopers? ¿Cuántos MessageQueue?
Manejador: múltiple, porque el método de destino de Mensaje se usa para marcar el Manejador al agregar y distribuir para lograr una distribución precisa, por lo que el mismo subproceso puede crear múltiples objetos Manejador.Looper: uno, para obtener el Looper, debe llamar al Looper .prepare()
primero, mire el código fuente a continuación y puede encontrar que si se incluyen varios objetos Looper, se lanzará una excepción.

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

MessageQueue: uno, cuando se llama a Looper.prepare(), juzgará si el Looper del hilo está vacío. Solo cuando esté vacío, se llamará al constructor de Looper para crear MessageQueue, por lo que solo hay uno.

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

Auto-introducción de habilidades de entrevista.

Ya es un proceso y procedimiento fijo para que el entrevistador se presente al comienzo de la entrevista, pero podemos mejorar nuestra competitividad a través de los siguientes puntos en este sentido: 1. El tiempo de autopresentación debe controlarse entre 1-3 minutos, y tenga cuidado de no exceder los 3 minutos
. Minuto
2. No use solo adjetivos sin experiencia específica. Use datos y resultados para expresar su propia experiencia. Por ejemplo, para expresar su habilidad técnica, puede usar el tiempo, la pila de tecnología y resultados como palabras clave para describir. Por ejemplo, use Google CameraX y Detect empaquetó un sdk de reconocimiento facial en aproximadamente 3 días, incluida la presentación de varias caras y caras individuales y la Vista que se puede usar como un paquete de reconocimiento facial.
3. Habla sobre tus propias ventajas y trata de acercarte a los requisitos del trabajo
4. Puedes empaquetarte apropiadamente durante la entrevista, pero recuerda no mentir

Supongo que te gusta

Origin blog.csdn.net/number_cmd9/article/details/123977367
Recomendado
Clasificación