Aunque la configuración del teléfono móvil que ejecuta Android
el teléfono móvil mejora constantemente, todavía no se puede PC
comparar con el teléfono móvil y no puede lograr PC
la gran memoria y el alto rendimiento del teléfono móvil CPU
. Por lo tanto, es imposible usar memoria y memoria ilimitadas al desarrollar Android
aplicaciones El uso inadecuado de la memoria y la memoria también causará problemas como congelación de aplicaciones y desbordamiento de memoria CPU
.CPU
1 Análisis de rendimiento de dibujo
Android
La aplicación necesita mostrar su cara de limpieza al usuario, y el usuario interactuará con la cara de limpieza, por lo que la fluidez de la interfaz es muy importante.
1.1 Principio de dibujo
View
Hay tres pasos en el proceso de dibujo de 3
, a saber measure
, layout
y draw
, que se ejecutan principalmente en la capa del marco de aplicación del sistema, mientras que los servicios Native
de la capa del sistema realizan la representación real de los datos en la pantalla.SurfaceFlinger
El proceso de dibujo se realiza principalmente CPU
mediante el trabajo de cálculo de datos de Measure
, Layout
, Record
, responsable de la rasterización y el renderizado. y (procesador de gráficos ) están conectados a través de la capa del controlador de gráficos, la capa del controlador de gráficos mantiene una cola, se agregará a la cola, para que los datos se puedan extraer de la cola.Execute
GPU
CPU
GPU
graphics processing unit
CPU
display list
GPU
Cuando se trata de rendimiento de dibujo, debemos mencionar el concepto de marco. El número de fotogramas es 1s
la cantidad de imágenes transmitidas en el tiempo, y también puede entenderse como cuántas veces el procesador de gráficos puede actualizar por segundo, representado por FPS
( Frames Per Second
). Cada cuadro es en realidad una imagen fija, y la ilusión de movimiento se crea mostrando cuadros en rápida sucesión. El ejemplo más sencillo es que cuando estamos jugando, si la pantalla está en , 60fps
no nos sentiremos atascados, pero si está más baja que 60fps
, por ejemplo 50fps
, nos sentiremos atascados. Esto se debe a que el cerebro humano recibirá y procesará continuamente la información que ven los globos oculares. Cuantos más fotogramas se procesen por unidad de tiempo, más eficazmente podrá ser reconocido por el cerebro. Se carga el número mínimo de fotogramas que el cerebro puede percibir. En este momento, el 10fps ~ 12fps
cerebro no está claro si la imagen es estática o cambiante.
Para mantener la pantalla en 60fps
, la pantalla debe 1s
actualizarse 60
una vez dentro de , es decir, no 16.6667ms
actualizarse una vez (el tiempo de dibujo está 16ms
dentro de ).
Android
16ms
El sistema envía una señal cada vez VSYNC
para activar UI
la representación de Si cada representación es exitosa, puede lograr lo que se requiere para una imagen fluida 60fps
, entonces, ¿qué es VSYNC
? VSYNC
Es Vertical Synchronization
la abreviatura de (Vertical Synchronization), que es una especie de interrupción de tiempo, una vez que VSYNC
se recibe la señal, CPU
comienza a procesar cada cuadro de datos. Si una operación cuesta tanto 24ms
que el sistema VSYNC
no puede procesar normalmente cuando recibe la señal, se producirán caídas de fotogramas. El usuario 32ms
verá el mismo marco en el archivo .
Hay muchas razones para tartamudear, las principales son las siguientes:
- el diseño
Layout
es demasiado complejo para16ms
representarlo dentro; - Se ejecutan demasiadas animaciones al mismo tiempo, lo que resulta en
CPU
unaGPU
sobrecarga; View
Sobredibujar, lo que hace que algunos píxeles se dibujen varias veces en el mismo tiempo de cuadro;UI
Se realizó una operación que consumió un poco de tiempo en el hilo ;GC
GC
El tiempo de pausa es demasiado largo o genera con frecuencia una gran cantidad de tiempo de pausa durante el reciclaje ;
1.2 Herramientas
1.2.1 Representación de GPU de perfil
Profile GPU Rendering es Android 4.1
una función de asistencia de desarrollo proporcionada por el sistema, que se puede activar en las opciones de desarrollador: Configuración -> Opciones de desarrollador -> Análisis de modo de procesamiento de GPU -> Mostrar como un gráfico de barras en la pantalla:
El eje horizontal de la figura representa el tiempo y el eje vertical representa el consumo de tiempo de un fotograma determinado. La línea horizontal verde es una línea de advertencia. Superar esta línea significa que se ha excedido la duración. Intente asegurarse de que el histograma de color vertical 16ms
permanece debajo de la línea verde. Estos histogramas de colores verticales representan un marco, y los histogramas de colores de diferentes colores representan diferentes significados:
- El naranja representa el tiempo de procesamiento, que es donde
CPU
le dice aGPU
renderizar un cuadro, esta es una llamada de bloqueo, porqueCPU
esperaráGPU
una respuesta al comando, si el histograma naranja es alto, significa queGPU
está muy ocupado; - El rojo representa el tiempo de ejecución, que es el tiempo
Android
de2D
renderizadoDisplay List
. Si el histograma rojo es alto, puede deberse a que se volvió a enviar la vista. También hay personalizaciones complejasView
que también harán que el histograma rojo sea más alto; - El azul representa el tiempo para medir el dibujo, es decir, cuánto se tarda en crearlo y actualizarlo
Display List
. Si el histograma azul es alto, es posible que deba volver a dibujarse o queView.onDraw()
el método maneja demasiadas cosas;
A medida que se actualice la interfaz, la interfaz mostrará el tiempo de procesamiento de cada cuadro con un histograma en tiempo real. Cuanto mayor sea el histograma, mayor será el tiempo de procesamiento. Cada histograma tiene una línea horizontal verde que representa el punto de referencia. Las líneas de columna marcadas 16ms
contienen tres partes (el azul representa Display List
el tiempo de medición del dibujo, el rojo representa el tiempo requerido para OpenGL
renderizar y el amarillo representa el tiempo de espera para el procesamiento), siempre que el tiempo total de cada cuadro sea inferior a la línea de base, no habrá tarjeta Ton problema (de hecho, no es un problema si algunos de ellos superan la línea de base).Display List
CPU
GPU
UI
1.2.2 GPU
Dibujo
Para optimizar el rendimiento, también puedes analizarlo a través de la herramienta de sobregiro UI
en las opciones de desarrollador . GPU
Después de activar la depuración en Configuración->Opciones de desarrollador-> GPU
Desbordamiento de depuración (diferentes dispositivos pueden tener diferentes ubicaciones o nombres), puede ver la siguiente imagen (analice el settings
desbordamiento actual de la interfaz):
Instrucciones a continuación:
Azul ( 1x
sobregirado), verde claro ( 2x
sobregirado), rojo claro ( 3x
sobregirado), rojo oscuro (sobregirado 4x
) representan 4
diferentes niveles de Overdraw
condiciones, nuestro objetivo es minimizar el rojo Overdraw
y ver más área azul.
Overdraw
A veces se debe UI
a muchas partes superpuestas del diseño y, a veces, a fondos superpuestos innecesarios. Por ejemplo, cierto Activity
objeto tiene un fondo, y luego los objetos dentro Layout
tienen su propio fondo, y al mismo tiempo, cada niño View
tiene su propio fondo. Con solo eliminar imágenes de fondo no esenciales, esto puede reducir muchas Overdraw
áreas rojas y aumentar la proporción de áreas azules. Esta medida puede mejorar significativamente el desempeño del programa.
Si ambos se pueden usar en el diseño RealtiveLayout
, LinearLayout
entonces úselo directamente LinearLayout
, porque Relativelayout
el diseño de es más complicado y lleva más CPU
tiempo dibujarlo. Si se requiere múltiple LinearLayout
o Framelayout
anidado, se puede usar Relativelayout
. Debido al anidamiento de varios niveles, se repite la mayor parte del dibujo del diseño, lo que reducirá el rendimiento del programa.
2 Herramienta de optimización de diseño: Inspector de diseño
Depurar diseños con las herramientas Inspector de diseño y Validación de diseño
3 Método de optimización de diseño
Hay muchos métodos de optimización del diseño, principalmente el uso racional del diseño include
, merge
y ViewStub
.
3.1 Uso razonable del diseño
Los diseños de uso común incluyen principalmente LinearLayout
, RelativeLayout
y , FrameLayout
etc. El uso razonable de ellos puede Android
reducir la carga de trabajo del dibujo y mejorar el rendimiento. Por ejemplo:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="布局优化" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Merge" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ViewStub" />
</LinearLayout>
</LinearLayout>
Puede ver que el diseño tiene tres capas:
El diseño tiene un total de 3
capas y contiene un total 5
de View
. Si RelativeLayout
se reescribe con , el código es el siguiente:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="布局优化" />
<TextView
android:id="@+id/tv_text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/tv_text1"
android:text="Merge" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/tv_text1"
android:layout_below="@+id/tv_text2"
android:text="ViewStub" />
</RelativeLayout>
Puedes ver que el diseño tiene dos capas:
Hay 2
capas en el diseño, y hay un total 4
de View
, se puede ver a partir de esto RelativeLayout
que el diseño de una capa se ha reducido. Si el diseño es complicado, se puede usar razonablemente RelativeLayout
para reducir el nivel del diseño. RelativeLayout
tiene un rendimiento menor que LinearLayout
, porque el arreglo RelativeLayout
de View
se basa en ser dependientes unos de otros.
Sin embargo, hay muchas situaciones que se enfrentan en el proceso de desarrollo real, y no es fácil decir quién tiene un mejor desempeño. En general, se recomienda usar si hay muchas capas de diseño RelativeLayout
y se recomienda usar si hay muchos diseños anidados LinearLayout
.
3.2 Usar include
etiquetas para reutilizar el diseño
Cuando varios diseños necesitan reutilizar el mismo diseño, como uno TitleBar
, si estas superficies de limpieza tienen que agregar este mismo diseño TitleBar
, será muy problemático mantenerlo, y TitleBar
el diseño debe copiarse en cada superficie de limpieza que debe agregarse. que es propenso a las omisiones. Si lo modifica TitleBar
, debe TitleBar
modificarlo en el diseño al que se hace referencia. Para resolver estos problemas, puede usar include
la etiqueta para resolver.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="40dp">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:src="@drawable/ic_launcher_background"
android:padding="3dp" />
</LinearLayout>
Este consta TitleBar
de ImageView
y TextView
. Vamos a TitleBar
introducir en el diseño utilizado anteriormente de la siguiente manera:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/title_bar" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="布局优化" />
<TextView
android:id="@+id/tv_text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/tv_text1"
android:text="Merge" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_text2"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/tv_text1"
android:text="ViewStub" />
</RelativeLayout>
</LinearLayout>
Puedes ver que el diseño tiene dos capas:
3.3 Usar merge
la etiqueta para eliminar capas redundantes
merge
Significa fusionar, y usar etiquetas en escenarios apropiados merge
puede reducir las capas redundantes. merge
Las etiquetas se usan generalmente include
junto con las etiquetas. Para el ejemplo de la sección anterior, si merge
se usa la etiqueta en su lugar LinearLayout
, el código es el siguiente:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="40dp">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:padding="3dp"
android:src="@drawable/ic_launcher_background" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="绘制优化" />
</merge>
Jerarquía de diseño:
Se puede ver que el anterior LinearLayout
ya no está, pero hay merge
una etiqueta para reemplazar LinearLayout
que hará LinearLayout
que falle y el diseño se estropeará. merge
Es mejor reemplazar la etiqueta FrameLayout
o tener la misma dirección de diseño LinearLayout
Por ejemplo, la dirección de diseño del diseño principal actual LinearLayout
es vertical y la línea de defensa del diseño del diseño secundario LinearLayout
también es vertical, por lo que puede usar merge
la etiqueta. Sin embargo, en este escenario, la dirección del diseño TitleBar
y el diseño LinearLayout
es horizontal, lo que obviamente no cumple con este requisito.
3.4 Uso ViewStub
para mejorar la velocidad de carga
Un escenario de desarrollo común es que no se muestran todos los controles en un diseño determinado, pero se muestra una parte de ellos. En este caso, el método general es usar y View
atributos GONE
. VISIBLE
Este método no es eficiente, aunque se logra el propósito de ocultar. , pero aún están en el diseño, el sistema aún los analizará y se pueden usar ViewStub
para resolver este problema.
ViewStub
es ligero View
, invisible y no ocupa espacio de diseño. Cuando está visible ViewStub
la llamada inflate
al método o la configuración, el sistema sujetará el ViewStub
diseño especificado y luego agregará este diseño a ViewStub
, antes de que esté visible la ViewStub
llamada inflate
al método o la configuración, no ocupa el espacio de diseño y los recursos del sistema, su propósito principal es El vista de destino ocupa una posición. Por lo tanto, el uso ViewStub
puede mejorar el rendimiento de la inicialización de limpieza, aumentando así la velocidad de carga de la interfaz. Primero, agregue una etiqueta al diseño ViewStub
:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ViewStub
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout="@layout/title_bar" />
</LinearLayout>
ViewStub
Use en la etiqueta android:layout
para referirse al diseño escrito anteriormente title_bar.xml
. Al ejecutar el programa, ViewStub
el diseño al que hace referencia la etiqueta no se puede mostrar porque el diseño no se cargó en ViewStub
y luego se usó en el código ViewStub
:
public class MainActivity extends AppCompatActivity {
private ViewStub viewStub;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewStub = findViewById(R.id.view_stub);
viewStub.inflate(); // 1
viewStub.setVisibility(View.VISIBLE); // 2
}
}
Los comentarios 1
y comentarios 2
se utilizan para colocar ViewStub
el diseño de la aplicación en el ViewStub
, de modo que se muestre el diseño de la aplicación. ViewStub
Preste atención a los siguientes problemas al usar :
ViewStub
Solo se puede cargar una vez, yViewStub
el objeto estará vacío después de la carga, por lo queViewStub
después de cargar el diseño al que hace referencia, no se puede usarViewStub
para controlar el diseño al que se hace referencia. Por lo tanto, si un control necesita mostrarse y ocultarse continuamente, aún es necesario usarView
elVisibility
atributo;ViewStub
no se pueden anidarmerge
etiquetas;ViewStub
La operación es el archivo de diseño, si solo desea operar el específicoView
, aún necesita usarView
elVisibility
atributo;
3.5 Optimización de dibujo
La optimización del dibujo significa principalmente que View.onDraw
el método debe evitar realizar una gran cantidad de operaciones:
onDraw
El método no necesita crear un nuevo objeto local, porqueonDraw
el método se ejecuta en tiempo real, lo que da como resultado una gran cantidad de objetos temporales, lo que genera un mayor uso de memoria y el sistema se ejecuta constantementeGC
, lo que reduce la eficiencia de ejecución;onDraw
El método no necesita realizar operaciones que consumen mucho tiempo, yonDraw
el ciclo se usa menos en el método, porque el ciclo tomará muchoCPU
tiempo. Conduce a un dibujo irregular, tartamudeo, etc. Google señaló oficialmente queView
la velocidad de cuadro de dibujo es estable en60dps
, lo que requiere que el tiempo de dibujo de cada cuadro no exceda16ms
(1000/60
). Aunque es difícil de garantizar, necesitamos reducirlo lo más posible;
60dps
Es la velocidad de visualización de imágenes más adecuada en la actualidad, y también es laAndroid
frecuencia de depuración establecida por la mayoría de los dispositivos.Si la operación de actualización de la interfaz se completa con éxito, se puede mostrar una imagen fluida, pero por algún motivo , la operación de actualización no se puede se completa cuando se recibe la señal. , se producirán caídas de fotogramas y la frecuencia de fotogramas de actualización disminuirá naturalmente (suponiendo que la frecuencia de fotogramas de actualización caiga baja , el usuario obviamente sentirá la congelación).16ms
VSYNC
60fps
30fps