Optimización del rendimiento de Android (3) - optimización de dibujo

Aunque la configuración del teléfono móvil que ejecuta Androidel teléfono móvil mejora constantemente, todavía no se puede PCcomparar con el teléfono móvil y no puede lograr PCla gran memoria y el alto rendimiento del teléfono móvil CPU. Por lo tanto, es imposible usar memoria y memoria ilimitadas al desarrollar Androidaplicaciones 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

AndroidLa 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

ViewHay tres pasos en el proceso de dibujo de 3, a saber measure, layouty draw, que se ejecutan principalmente en la capa del marco de aplicación del sistema, mientras que los servicios Nativede la capa del sistema realizan la representación real de los datos en la pantalla.SurfaceFlinger

El proceso de dibujo se realiza principalmente CPUmediante 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.ExecuteGPUCPUGPUgraphics processing unitCPUdisplay listGPU

Cuando se trata de rendimiento de dibujo, debemos mencionar el concepto de marco. El número de fotogramas es 1sla 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 , 60fpsno 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 ~ 12fpscerebro no está claro si la imagen es estática o cambiante.

Para mantener la pantalla en 60fps, la pantalla debe 1sactualizarse 60una vez dentro de , es decir, no 16.6667msactualizarse una vez (el tiempo de dibujo está 16msdentro de ).

Android16msEl sistema envía una señal cada vez VSYNCpara activar UIla representación de Si cada representación es exitosa, puede lograr lo que se requiere para una imagen fluida 60fps, entonces, ¿qué es VSYNC? VSYNCEs Vertical Synchronizationla abreviatura de (Vertical Synchronization), que es una especie de interrupción de tiempo, una vez que VSYNCse recibe la señal, CPUcomienza a procesar cada cuadro de datos. Si una operación cuesta tanto 24msque el sistema VSYNCno puede procesar normalmente cuando recibe la señal, se producirán caídas de fotogramas. El usuario 32msverá el mismo marco en el archivo .

Hay muchas razones para tartamudear, las principales son las siguientes:

  • el diseño Layoutes demasiado complejo para 16msrepresentarlo dentro;
  • Se ejecutan demasiadas animaciones al mismo tiempo, lo que resulta en CPUuna GPUsobrecarga;
  • ViewSobredibujar, lo que hace que algunos píxeles se dibujen varias veces en el mismo tiempo de cuadro;
  • UISe realizó una operación que consumió un poco de tiempo en el hilo ;
  • GCGCEl 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.1una 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:

Análisis del modo GPU

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 16mspermanece 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 CPUle dice a GPUrenderizar un cuadro, esta es una llamada de bloqueo, porque CPUesperará GPUuna respuesta al comando, si el histograma naranja es alto, significa que GPUestá muy ocupado;
  • El rojo representa el tiempo de ejecución, que es el tiempo Androidde 2Drenderizado Display List. Si el histograma rojo es alto, puede deberse a que se volvió a enviar la vista. También hay personalizaciones complejas Viewque 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 que View.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 16mscontienen tres partes (el azul representa Display Listel tiempo de medición del dibujo, el rojo representa el tiempo requerido para OpenGLrenderizar 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 ListCPUGPUUI

1.2.2 GPUDibujo

Para optimizar el rendimiento, también puedes analizarlo a través de la herramienta de sobregiro UIen las opciones de desarrollador . GPUDespués de activar la depuración en Configuración->Opciones de desarrollador-> GPUDesbordamiento de depuración (diferentes dispositivos pueden tener diferentes ubicaciones o nombres), puede ver la siguiente imagen (analice el settingsdesbordamiento actual de la interfaz):

dibujo de GPU

Instrucciones a continuación:

Girar en descubierto

Azul ( 1xsobregirado), verde claro ( 2xsobregirado), rojo claro ( 3xsobregirado), rojo oscuro (sobregirado 4x) representan 4diferentes niveles de Overdrawcondiciones, nuestro objetivo es minimizar el rojo Overdrawy ver más área azul.

OverdrawA veces se debe UIa muchas partes superpuestas del diseño y, a veces, a fondos superpuestos innecesarios. Por ejemplo, cierto Activityobjeto tiene un fondo, y luego los objetos dentro Layouttienen su propio fondo, y al mismo tiempo, cada niño Viewtiene 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, LinearLayoutentonces úselo directamente LinearLayout, porque Relativelayoutel diseño de es más complicado y lleva más CPUtiempo dibujarlo. Si se requiere múltiple LinearLayouto Framelayoutanidado, 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, mergey ViewStub.

3.1 Uso razonable del diseño

Los diseños de uso común incluyen principalmente LinearLayout, RelativeLayouty , FrameLayoutetc. El uso razonable de ellos puede Androidreducir 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:

jerarquía de diseño

El diseño tiene un total de 3capas y contiene un total 5de View. Si RelativeLayoutse 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:

jerarquía de diseño

Hay 2capas en el diseño, y hay un total 4de View, se puede ver a partir de esto RelativeLayoutque el diseño de una capa se ha reducido. Si el diseño es complicado, se puede usar razonablemente RelativeLayoutpara reducir el nivel del diseño. RelativeLayouttiene un rendimiento menor que LinearLayout, porque el arreglo RelativeLayoutde Viewse 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 RelativeLayouty se recomienda usar si hay muchos diseños anidados LinearLayout.

3.2 Usar includeetiquetas 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 TitleBarel diseño debe copiarse en cada superficie de limpieza que debe agregarse. que es propenso a las omisiones. Si lo modifica TitleBar, debe TitleBarmodificarlo en el diseño al que se hace referencia. Para resolver estos problemas, puede usar includela 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 TitleBarde ImageViewy TextView. Vamos a TitleBarintroducir 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:

jerarquía de diseño

3.3 Usar mergela etiqueta para eliminar capas redundantes

mergeSignifica fusionar, y usar etiquetas en escenarios apropiados mergepuede reducir las capas redundantes. mergeLas etiquetas se usan generalmente includejunto con las etiquetas. Para el ejemplo de la sección anterior, si mergese 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:

jerarquía de diseño

Se puede ver que el anterior LinearLayoutya no está, pero hay mergeuna etiqueta para reemplazar LinearLayoutque hará LinearLayoutque falle y el diseño se estropeará. mergeEs mejor reemplazar la etiqueta FrameLayouto tener la misma dirección de diseño LinearLayoutPor ejemplo, la dirección de diseño del diseño principal actual LinearLayoutes vertical y la línea de defensa del diseño del diseño secundario LinearLayouttambién es vertical, por lo que puede usar mergela etiqueta. Sin embargo, en este escenario, la dirección del diseño TitleBary el diseño LinearLayoutes horizontal, lo que obviamente no cumple con este requisito.

3.4 Uso ViewStubpara 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 Viewatributos GONE. VISIBLEEste 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 ViewStubpara resolver este problema.

ViewStubes ligero View, invisible y no ocupa espacio de diseño. Cuando está visible ViewStubla llamada inflateal método o la configuración, el sistema sujetará el ViewStubdiseño especificado y luego agregará este diseño a ViewStub, antes de que esté visible la ViewStubllamada inflateal 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 ViewStubpuede 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>

ViewStubUse en la etiqueta android:layoutpara referirse al diseño escrito anteriormente title_bar.xml. Al ejecutar el programa, ViewStubel diseño al que hace referencia la etiqueta no se puede mostrar porque el diseño no se cargó en ViewStuby 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 1y comentarios 2se utilizan para colocar ViewStubel diseño de la aplicación en el ViewStub, de modo que se muestre el diseño de la aplicación. ViewStubPreste atención a los siguientes problemas al usar :

  • ViewStubSolo se puede cargar una vez, y ViewStubel objeto estará vacío después de la carga, por lo que ViewStubdespués de cargar el diseño al que hace referencia, no se puede usar ViewStubpara controlar el diseño al que se hace referencia. Por lo tanto, si un control necesita mostrarse y ocultarse continuamente, aún es necesario usar Viewel Visibilityatributo;
  • ViewStubno se pueden anidar mergeetiquetas;
  • ViewStubLa operación es el archivo de diseño, si solo desea operar el específico View, aún necesita usar Viewel Visibilityatributo;

3.5 Optimización de dibujo

La optimización del dibujo significa principalmente que View.onDrawel método debe evitar realizar una gran cantidad de operaciones:

  • onDrawEl método no necesita crear un nuevo objeto local, porque onDrawel 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 constantemente GC, lo que reduce la eficiencia de ejecución;
  • onDrawEl método no necesita realizar operaciones que consumen mucho tiempo, y onDrawel ciclo se usa menos en el método, porque el ciclo tomará mucho CPUtiempo. Conduce a un dibujo irregular, tartamudeo, etc. Google señaló oficialmente que Viewla velocidad de cuadro de dibujo es estable en 60dps, lo que requiere que el tiempo de dibujo de cada cuadro no exceda 16ms( 1000/60). Aunque es difícil de garantizar, necesitamos reducirlo lo más posible;

60dpsEs 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).16msVSYNC60fps30fps

Supongo que te gusta

Origin blog.csdn.net/xingyu19911016/article/details/128815711
Recomendado
Clasificación