Embora a configuração do telefone celular que executa Android
o telefone celular esteja melhorando constantemente, ainda não pode ser PC
comparada com o telefone celular e não pode alcançar PC
a grande memória e o alto desempenho do telefone celular CPU
. Portanto, é impossível usar memória e memória ilimitadas ao desenvolver Android
aplicativos CPU
. CPU
O uso inadequado de memória e memória também causará problemas como congelamento de aplicativos e estouro de memória.
1 Análise de desempenho do desenho
Android
O aplicativo precisa exibir seu rosto de limpeza para o usuário, e o usuário irá interagir com o rosto de limpeza, então a fluência da interface é muito importante.
1.1 Princípio do desenho
View
Existem três etapas no processo de desenho de 3
, a saber measure
, , layout
e draw
, que são executados principalmente na camada de estrutura do aplicativo do sistema, enquanto a renderização real dos dados na tela é feita pelos serviços Native
da camada do sistema .SurfaceFlinger
O processo de desenho é realizado principalmente CPU
pelo trabalho de cálculo de dados de Measure
, Layout
, Record
, responsável pela rasterização e renderização. e (processador gráfico ) estão conectados através da camada do driver gráfico, a camada do driver gráfico mantém uma fila, será adicionada à fila, para que os dados possam ser retirados da fila.Execute
GPU
CPU
GPU
graphics processing unit
CPU
display list
GPU
Quando se trata de desempenho de desenho, precisamos mencionar o conceito de quadro. O número de quadros é 1s
a quantidade de imagens transmitidas no tempo, e também pode ser entendido como quantas vezes o processador gráfico pode atualizar por segundo, representado por FPS
( Frames Per Second
). Cada quadro é, na verdade, uma imagem estática, e a ilusão de movimento é criada pela exibição de quadros em rápida sucessão. O exemplo mais simples é que, quando estamos jogando, se a tela estiver em , 60fps
não nos sentiremos presos, mas se estiver abaixo de 60fps
, por exemplo 50fps
, nos sentiremos presos. Isso ocorre porque o cérebro humano recebe e processa continuamente as informações vistas pelos globos oculares. Quanto mais quadros processados por unidade de tempo, mais efetivamente eles podem ser reconhecidos pelo cérebro. O número mínimo de quadros que o cérebro pode perceber é carregado. Neste momento, o 10fps ~ 12fps
cérebro não está claro se a imagem é estática ou mutável.
Para manter a tela em 60fps
, a tela precisa ser 1s
atualizada 60
uma vez dentro de , ou seja, não 16.6667ms
ser atualizada uma vez (o tempo de desenho está 16ms
dentro de ).
Android
16ms
O sistema envia um sinal a cada VSYNC
para acionar UI
a renderização de .Se cada renderização for bem-sucedida, pode alcançar o que é necessário para uma imagem suave 60fps
, então o que é isso VSYNC
? VSYNC
É Vertical Synchronization
a abreviação de (Vertical Synchronization), que é uma espécie de interrupção de temporização, uma vez que VSYNC
o sinal é recebido, CPU
ele começa a processar cada quadro de dados. Se uma operação custa tanto 24ms
que o sistema VSYNC
não consegue renderizar normalmente quando recebe o sinal, ocorrerão quedas de quadro. O usuário 32ms
verá o mesmo quadro no arquivo .
Existem muitas razões para a gagueira, as principais são as seguintes:
- o layout
Layout
é muito complexo para16ms
ser renderizado; - Muitas animações são executadas ao mesmo tempo, resultando em
CPU
ouGPU
sobrecarregadas; View
Overdrawing, fazendo com que alguns pixels sejam desenhados várias vezes no mesmo tempo de quadro;UI
Uma operação um pouco demorada foi feita no thread ;GC
GC
O tempo de pausa é muito longo ou freqüentemente gera muito tempo de pausa durante a reciclagem ;
1.2 Ferramentas
1.2.1 Renderização de GPU de perfil
Profile GPU Rendering é Android 4.1
uma função de assistência ao desenvolvimento fornecida pelo sistema, que pode ser ativada nas opções do desenvolvedor: Settings –> Developer Options –> GPU Rendering Mode Analysis –> Display como um gráfico de barras na tela:
O eixo horizontal na figura representa o tempo e o eixo vertical representa o consumo de tempo de um determinado quadro. A linha horizontal verde é uma linha de aviso. Exceder esta linha significa que a duração foi excedida. Tente garantir que o histograma de cor vertical 16ms
permaneça abaixo da linha verde. Esses histogramas coloridos verticais representam um quadro, e os histogramas coloridos de cores diferentes representam significados diferentes:
- Laranja representa o tempo de processamento, que é onde
CPU
diz paraGPU
renderizar um frame.Esta é uma chamada de bloqueio, poisCPU
irá aguardarGPU
uma resposta ao comando.Se o histograma laranja estiver alto, significa queGPU
está muito ocupado; - Vermelho representa o tempo de execução, que é o tempo
Android
de2D
renderizaçãoDisplay List
. Se o histograma vermelho estiver alto, pode ser causado pelo reenvio da visualização. Existem também personalizações complexasView
que também farão com que o histograma vermelho fique mais alto; - O azul representa o tempo de medição do desenho, ou seja, quanto tempo leva para criar e atualizar
Display List
. Se o histograma azul estiver alto, pode ser necessário redesenhá-lo ouView.onDraw()
o método manipula muitas coisas;
À medida que a interface é atualizada, ela exibirá o tempo de renderização de cada quadro com um histograma em tempo real. Quanto maior o histograma, maior o tempo de renderização. Cada histograma tem uma linha horizontal verde representando a referência. As linhas de coluna marcadas 16ms
contêm três partes (azul representa Display List
o tempo de medição do desenho, vermelho representa o tempo necessário para OpenGL
renderização e amarelo representa o tempo de espera para processamento), desde que o tempo total de cada quadro seja menor que a linha de base, não haverá cartão Ton problema (na verdade, não é um problema se alguns deles excederem a linha de base).Display List
CPU
GPU
UI
1.2.2 GPU
Desenho
Para otimização de desempenho, você também pode analisá-lo por meio da ferramenta overdraw UI
nas opções do desenvolvedor . GPU
Depois de ativar a depuração em Configurações->Opções do desenvolvedor->Depurar GPU
overdraw (dispositivos diferentes podem ter locais ou nomes diferentes), você pode ver a seguinte imagem (analisar o settings
overdraw da interface atual):
Instruções abaixo:
Azul ( 1x
overdrawn), verde claro ( 2x
overdrawn), vermelho claro ( 3x
overdrawn), vermelho escuro (overdrawn 4x
) representam 4
diferentes níveis de Overdraw
condições, nosso objetivo é minimizar o vermelho Overdraw
e ver mais área azul.
Overdraw
Às vezes, é por causa UI
de muitas partes sobrepostas do layout e, às vezes, por causa de planos de fundo sobrepostos desnecessários. Por exemplo, um determinado Activity
objeto tem um plano de fundo e, em seguida, os objetos dentro dele Layout
têm seu próprio plano de fundo e, ao mesmo tempo, cada criança View
tem seu próprio plano de fundo. Apenas removendo imagens de fundo não essenciais, isso pode reduzir muitas Overdraw
áreas vermelhas e aumentar a proporção de áreas azuis. Esta medida pode melhorar significativamente o desempenho do programa.
Se ambos puderem ser usados no layout RealtiveLayout
, LinearLayout
então use diretamente LinearLayout
, pois Relativelayout
o layout de é mais complicado, e leva mais CPU
tempo para desenhar. Se múltiplos LinearLayout
ou Framelayout
aninhados forem necessários, eles podem ser usados Relativelayout
. Devido ao aninhamento de vários níveis, a maior parte do desenho do layout é repetida, o que reduzirá o desempenho do programa.
2 Ferramenta de otimização de layout—Layout Inspector
Depurar layouts com as ferramentas Layout Inspector e Layout Validation
3 Método de otimização de layout
Existem muitos métodos de otimização de layout, incluindo principalmente o uso racional de layout include
, merge
e ViewStub
.
3.1 Uso razoável do layout
Layouts comumente usados incluem principalmente LinearLayout
, RelativeLayout
e , FrameLayout
etc. O uso razoável deles pode Android
reduzir a carga de trabalho do desenho e melhorar o desempenho. por exemplo:
<?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>
Você pode ver que o layout tem três camadas:
O layout tem um total de 3
camadas e contém um total 5
de View
. Se RelativeLayout
reescrito com , o código fica da seguinte forma:
<?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>
Você pode ver que o layout tem duas camadas:
Existem 2
camadas no layout, e há um total 4
de View
, pode-se ver RelativeLayout
que o layout de uma camada foi reduzido. Se o layout for complicado, pode ser razoavelmente usado RelativeLayout
para reduzir o nível do layout. RelativeLayout
tem desempenho inferior a LinearLayout
, porque o arranjo RelativeLayout
de View
é baseado na dependência um do outro.
No entanto, existem muitas situações enfrentadas no processo de desenvolvimento real e não é fácil dizer qual desempenho é melhor. Em geral, é recomendável usar se houver muitas camadas de layout RelativeLayout
e se houver muitos layouts aninhados LinearLayout
.
3.2 Use include
tags para reutilização de layout
Quando vários layouts precisam reutilizar o mesmo layout, como um TitleBar
, se essas superfícies de limpeza tiverem que adicionar o mesmo layout TitleBar
, será muito problemático manter, e TitleBar
o layout precisa ser copiado para cada superfície de limpeza que precisa ser adicionada, que é propenso a omissões. Se você modificá TitleBar
-lo, precisará TitleBar
modificá-lo no layout referenciado. Para resolver esses problemas, você pode usar include
o rótulo 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>
Isso consiste TitleBar
em ImageView
e TextView
. Vamos TitleBar
introduzir no layout usado anteriormente da seguinte forma:
<?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>
Você pode ver que o layout tem duas camadas:
3.3 Use merge
o rótulo para remover camadas redundantes
merge
Isso significa mesclar e usar tags em cenários apropriados merge
pode reduzir camadas redundantes. merge
Tags são geralmente include
usadas em conjunto com tags. Para o exemplo da seção anterior, se merge
a tag for usada em vez disso LinearLayout
, o código será o seguinte:
<?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>
Hierarquia de layout:
Pode-se ver que o anterior LinearLayout
se foi, mas há merge
uma tag para substituir LinearLayout
o que fará com LinearLayout
que o falhe e o layout fique bagunçado. merge
É melhor substituir o rótulo FrameLayout
ou ter a mesma direção de layout LinearLayout
. Por exemplo, a direção do layout pai atual LinearLayout
é vertical e a linha de defesa do layout filho contido LinearLayout
também é vertical, então você pode usar merge
o rótulo. No entanto, neste cenário, a direção do layout TitleBar
e o layout LinearLayout
são horizontais, o que obviamente não atende a esse requisito.
3.4 Use ViewStub
para melhorar a velocidade de carregamento
Um cenário de desenvolvimento comum é que nem todos os controles em um determinado layout são exibidos, mas uma parte deles é exibida. Nesse caso, o método geral é usar View
atributos e GONE
. VISIBLE
Esse método não é eficiente, embora o propósito de ocultar seja alcançado , mas eles ainda estiverem no layout, o sistema ainda os analisará e poderá ser usado ViewStub
para resolver esse problema.
ViewStub
é leve View
, invisível e não ocupa espaço no layout. Ao ViewStub
chamar inflate
o método ou configuração é visível, o sistema irá fixar o ViewStub
layout especificado e, em seguida, adicionar esse layout a ViewStub
, antes ViewStub
de chamar inflate
o método ou configuração é visível, ele não ocupa o espaço de layout e os recursos do sistema, seu principal objetivo é O vista de destino ocupa uma posição. Portanto, o uso ViewStub
pode melhorar o desempenho da inicialização de limpeza, aumentando assim a velocidade de carregamento da interface. Primeiro, adicione uma tag ao layout 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 na tag android:layout
para se referir ao layout escrito anteriormente title_bar.xml
. Ao executar o programa, ViewStub
o layout referenciado pelo rótulo não pode ser exibido, porque o layout não foi carregado em ViewStub
, e então usado no 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
}
}
Os comentários 1
e comentários 2
são usados para colocar ViewStub
o layout do aplicativo no ViewStub
, para que o layout do aplicativo seja exibido. ViewStub
Preste atenção aos seguintes problemas ao usar :
ViewStub
Ele só pode ser carregado uma vez eViewStub
o objeto ficará vazio após o carregamento, portanto,ViewStub
após o carregamento do layout referenciado por, ele não poderá ser usadoViewStub
para controlar o layout referenciado. Portanto, se um controle precisa ser exibido e ocultado continuamente, ainda é necessário usarView
oVisibility
atributo;ViewStub
não pode aninharmerge
tags;ViewStub
A operação é o arquivo de layout, se você quiser apenas operar o específicoView
, ainda precisará usarView
oVisibility
atributo;
3.5 Otimização do Desenho
A otimização do desenho significa principalmente que View.onDraw
o método precisa evitar a realização de um grande número de operações:
onDraw
O método não precisa criar um novo objeto local, poisonDraw
o método é executado em tempo real, resultando em um grande número de objetos temporários, resultando em mais uso de memória, e o sistema fica rodando constantementeGC
, diminuindo a eficiência da execução;onDraw
O método não precisa executar operações demoradas eonDraw
o loop é menos usado no método, porque o loop levará muitoCPU
tempo. Levando a um desenho irregular, gagueira e assim por diante. O Google apontou oficialmente queView
a taxa de quadros de desenho é estável em60dps
, o que exige que o tempo de desenho de cada quadro não exceda16ms
(1000/60
). Embora seja difícil de garantir, precisamos reduzi-lo ao máximo;
60dps
É a velocidade de exibição de imagem mais adequada no momento e também é Android
a frequência de depuração definida pela maioria dos dispositivos. 16ms
Se a operação de atualização da interface for concluída com sucesso, uma imagem suave pode ser exibida, mas por qualquer motivo VSYNC
, a operação de atualização não pode ser concluído quando o sinal é recebido. , ocorrerão quedas de quadros e a taxa de quadros de atualização cairá naturalmente (supondo que a taxa de quadros de atualização 60fps
caia baixo 30fps
, o usuário obviamente sentirá o congelamento).