Red de conocimiento informático - Conocimiento informático - El secreto de la capa de visualización de Android

El secreto de la capa de visualización de Android

Recientemente, recibí una función de control de voz. La implementación específica es cubrir la aplicación de interfaz de usuario con una capa táctil transparente anti-accidentes para evitar que los usuarios hagan clic en el estado de voz, pero no puede afectar el control del diálogo de tecla de retorno físico. al mismo tiempo, para la tecla de retorno no física Dialog También evite operaciones al llamar. La función parece complicada, por eso usamos una imagen para ilustrarla.

No es difícil ver en la imagen que la capa de control de voz que queremos implementar está en realidad entre la vista de la aplicación y el cuadro de mensaje interno sobre la vista, y también es una capa debajo del botón emergente de retorno. ventana arriba. Debido a que la exploración de la jerarquía de vistas de Android no ha sido muy profunda, aproveché la oportunidad de realizar esta función para resumir y ordenar el conocimiento de la jerarquía de vistas de Android.

Primero, aclaremos varios conceptos importantes de Window, DecorView y mContentParent a través de un diagrama de jerarquía.

En Android, ya sea Activity, Toast, ActionBar o Dialog, sus vistas están adjuntas a Window. De hecho, básicamente todas las vistas se presentan simultáneamente a través de Window, por lo que Window puede entenderse como el portador y administrador de la vista. Hay tres tipos de ventanas: ventana de aplicación, ventana secundaria y ventana del sistema. La ventana de la aplicación corresponde a una actividad. Una ventana secundaria no puede existir sola. Debe estar adjunta a una ventana principal específica. Por ejemplo, algunos cuadros de diálogo comunes son una ventana secundaria que necesita declarar permisos. se puede crear, como Toast y La barra de estado del sistema es la ventana del sistema. DecorView es una subclase de FrameLayout que contiene LinearLayout con ActionBar y mContentParent.

mContentParent puede ser un nombre extraño, pero es el diseño raíz de la aplicación, que es una subclase de android.R.id.content.DecorView. Eliminar.contenido. setContentView en Actividad es en realidad un diseño XML convertido a Ver a través de LayoutInflater y agregado a mContentParent.

Cada actividad contiene una ventana y, en Android, la ventana tiene solo una clase de implementación PhoneWindow, por lo que cada actividad contiene una PhoneWindow, que contiene la vista de nivel superior DecorView. ¿Cómo establece Activity contacto con PhoneWindow? Averigüemos a través del código fuente:

Durante el proceso de inicio de Activity, se ejecutará el método ActivityThread performLaunchActivity, que llama al adjunto de la actividad. El método adjuntar () crea una instancia de la mWindow mantenida por la Actividad. Dado que la Actividad implementa la interfaz de devolución de llamada de la Ventana, cuando la Ventana recibe un cambio de estado del mundo externo, volverá a llamar al método de la Actividad.

Como puede ver, hay una variable miembro DecorView dentro de PhoneWindow, que es una clase dentro de PhoneWindow y hereda de FrameLayout.

Este es el método setContentView que llamaremos cada vez que escribamos una Actividad. El método setContentView llama internamente a setContentView de getWindow (), y esta mWindow es PhoneWindow.

Vemos que hay tres métodos setContentView sobrecargados en PhoneWindow. En setContentView (int layoutResID), primero se juzga mContentParent. Si mContentParent está vacío, es decir, cuando se llama por primera vez, se ejecuta el método installDecor (), se crea un DecorView y se agrega a mContentParent. Si mContentParent no está vacío, elimina la vista de mContentParent. Luego, el XML se convierte en un árbol de vistas mediante mLayoutInflater y se agrega a la vista mContentParent. Una vez completada la adición, la notificación de devolución de llamada onContentChanged indica que la carga de la interfaz se ha completado.

Primero determine si mDecor está vacío. Si está vacío, genere DecorView. En segundo lugar, configure la capacidad de DecorView para obtener el foco en FOCUS_AFTER_DESCENDANTS, es decir, primero asígnelo a las subvistas para su procesamiento. no ha sido procesado, luego lo maneja nuevamente por sí solo. La primera vez que DecorView no se carga en mContentParent, por lo que mContentParent está vacío, llame a generateLayout para agregar el contenido de setContentView a mContentParent.

Al personalizar la barra de acciones o la pantalla completa de la actividad, debes saber que el método requesetFeature debe llamarse antes que setContentView por este motivo. setContentView esencialmente activa el estado restaurado de la actividad, que a su vez activa el método makeVisible.

En WindowManager, getWindow().getAttributes() se utiliza como parámetro de diseño:

Puede ver que el tipo de ventana de Actividad es TYPE_APPLICATION y el tipo TYPE determina la visualización. nivel en la capa de la ventana. Este tipo de TIPO determina el nivel de visualización en la capa de ventana. El tipo de TIPO se resume a continuación:

El cuadro de diálogo no pertenece a la vista, es una ventana secundaria de la aplicación, por eso. No podemos agregar una vista en mContentParent para lograr el motivo de proteger el cuadro de diálogo. La ventana en el cuadro de diálogo también se implementa mediante el método makeNewWindow de PolicyManager. Los cuadros de diálogo ordinarios deben utilizar el contexto de la Actividad. Si se utiliza el contexto de la aplicación, se informará un error. Esto se debe a que no existe una etiqueta de aplicación, que solo pertenece a la actividad. El TIPO de un cuadro de diálogo normal es TYPE_APPLICATION_ATTACHED_DIALOG. A través de diferentes niveles de TIPO, podemos encontrar los atributos de WindowManager LayoutParams colocados encima del cuadro de diálogo normal, como TYPE_SYSTEM_ALERT y TYPE_TOAST. TYPE_TOAST, están configurados para anular por completo los cuadros de diálogo normales.

La diferencia entre ellos es que uno es un cuadro de diálogo a nivel del sistema y el otro es un brindis, y el cuadro de diálogo del sistema debe solicitar permisos. Por lo tanto, nuestra primera solución es usar el cuadro de diálogo normal como cuadro de diálogo enmascarable y usar TYPE_SYSTEM_ALERT como cuadro de mensaje de voz, pero todos sabemos que Android tiene un problema inevitable, es decir, la "seguridad" del fabricante. Considere la personalización en la capa de marco de la MUI para deshabilitar a los usuarios de forma predeterminada.

El marco MUI es un marco de MUI que deshabilita el privilegio de ventana flotante del usuario de forma predeterminada, lo que significa que las vistas con el atributo TYPE_SYSTEM_ALERT no se pueden mostrar de forma predeterminada y el usuario debe habilitar manualmente el privilegio después de habilitarlo. Ábrelo para mostrarlo.

Aunque puede saltar a la página de permisos al inicio según el modelo del usuario, como desarrollador emocional, esta experiencia imperfecta es inaceptable. Según nuestro conocimiento previo de la jerarquía de vistas de Android, tenemos un segundo conjunto de opciones. La vista de la aplicación se almacena en mContentParent y Activity, y pertenece al nivel más bajo con la jerarquía de ventanas TYPE_APPLICATION. La jerarquía de diálogo normal es TYPE_APPLICATION_ATTACHED_DIALOG, por lo que no nos es posible usar el diálogo normal como nivel superior, por lo que usamos el. Diálogo normal como el cuadro de recordatorio no protegido La capa superior, y debajo de esto solo debemos considerar las dos capas de ventanas emergentes bloqueables y el control de voz. Debido a que la capa de control de voz debe poder bloquear la ventana emergente, debemos colocar la capa de control de voz en la capa superior de la ventana emergente. Después del aprendizaje anterior, agregamos la ventana emergente. mContentParent y agregue la capa de control de voz a la capa DecorView, por lo que resuelve este problema perfectamente. mContentParent es un FrameLayout. La vista de la aplicación se pasa a mContentParent a través de mContentParent. La vista de la aplicación se agrega a mContentParent a través de sentContentView. Como ventana emergente, el orden de adición debe ser relativo a las vistas de la aplicación posteriores, por lo que cuando aparece el mensaje. Si se agrega nuevamente la ventana emergente a mContentParent, se agregará a la vista de la aplicación. DecorView es el contenedor principal de mContentParent, que también es un FrameLayout. Al agregar un cuadro de mensaje de voz, mContentParent ya debe existir, por lo que se agregará en la parte superior de mContentParent.

De esta manera, se exploró un requerimiento aparentemente complejo a través del código fuente de Android para encontrar una solución perfecta. Muchas veces cuando nos encontramos con problemas difíciles de resolver, intentamos volver al origen del mismo. problema y pensar en el problema. Su naturaleza a menudo conducirá a diferentes descubrimientos.