1. Desenho de transição
Um determinado pixel na tela é repetidamente desenhado várias vezes em um quadro, que é um desenho de transição.
A imagem abaixo mostra vários cartões caindo juntos, mas apenas o primeiro cartão é totalmente visível. As cartas atrás são apenas parcialmente visíveis. No entanto, o sistema Android desenha as cartas inferiores ao comprar e, em seguida, desenha as cartas superiores. Mas, na verdade, a parte invisível da carta inferior não precisa ser sacada, apenas a parte visível precisa ser sacada.
De acordo com o nível de desenho de transição, pode ser dividido em:
- Desenhe sem transições (um pixel é desenhado apenas uma vez)
- desenho de transição x1 (um pixel é desenhado duas vezes)
- desenho de transição x2 (um pixel é desenhado três vezes)
- Overdraw x3 (um pixel é desenhado quatro vezes)
- Overdraw x4+ (um pixel é desenhado mais de cinco vezes)
2. Visualize o desenho de transição do seu aplicativo
Método 1: ativar a depuração de renderização de transição de GPU por meio das opções do desenvolvedor
Nas opções do desenvolvedor do telefone Android, há uma opção de "depurar overdrawing da GPU":
Depois de clicar nele, selecione "Mostrar área de desenho de transição":
Método 2: habilitar a depuração de renderização de transição de GPU por meio do comando adb
Obviamente, se for problemático inserir as configurações do sistema todas as vezes, você pode usar o comando adb para ativá-lo e desativá-lo:
ative "Depurar overdrawing de GPU":
adb shell setprop debug.hwui.overdraw show
Desative "Debug GPU Overdraw":
adb shell setprop debug.hwui.overdraw false
Pode ser necessário reiniciar o aplicativo que você está desenvolvendo no momento após a execução do comando.
Cor e desenho de transição:
- Cores primárias: sem overdraw
- Azul: 1 overdraw
- Verde: 2 overdraws
- Rosa: 3 overdraws
- Vermelho: 4 ou mais overdraws
No desenvolvimento normal, se houver uma situação de desenho de transição de rosa e acima. As instruções para overdrawing também são bastante severas. Precisa ser otimizado.
3. Otimize o desenho de transição
1. Remova a cor de fundo padrão que acompanha a atividade:
Visualize o tema Theme no código-fonte do Android, da seguinte maneira:
<style name="Theme">
...
<!-- Window attributes -->
<item name="windowBackground">@drawable/screen_background_selector_dark</item>
...
</style>
Ou seja, herdando o estilo do Tema, por padrão, a criação de uma nova Atividade tem um fundo. Em circunstâncias normais, muitas interfaces não precisam de fundo.
A seguir está a página inicial do aplicativo meteorológico integrado da Huawei. Podemos ver que o texto e os ícones são verdes. A superfície já está desenhada na terceira camada de transição. O mapa meteorológico atrás dele é uma camada e o texto é outra camada. É normal. Diz-se que deve haver apenas duas camadas, ou seja, o texto e os ícones devem ser azuis.
Em seguida, essa camada extra deve ter a cor de fundo que vem com a atividade. Isso é definido no tema.
Só precisamos remover a cor de fundo em nosso AppTheme:
<style name="AppTheme" parent="android:Theme.Light.NoTitleBar">
<item name="android:windowBackground">@null</item>
</style>
Ou no método onCreate da Activity:
getWindow().setBackgroundDrawable(null);
2. Use os métodos clipRect e clipPath do Canvas para limitar a área de desenho do View
Uma Activity corresponde a um Canvas, que é a tela. O conceito da tela é uma prancheta de desenho. Essa tela fornece muitas APIs. Podemos desenhar e fazer algumas operações na tela chamando a API da tela. O método clipRect é usado para cortar a tela. Uma área retangular de, que é descrita por um objeto Rect. Depois de chamar clipRect, a área desenhável da tela é reduzida para o mesmo tamanho da área retangular especificada por Rect. Todo o desenho será limitado a este retângulo. O conceito de recorte aqui é semelhante ao do PS.
Um exemplo típico, layout de gaveta, encontrei Netease Cloud Music para fazer a cirurgia:
Preste atenção para observar que quando a gaveta esquerda é aberta, o layout da gaveta se sobrepõe ao layout traseiro. Nesse momento, mais da metade da tela inteira fica vermelha e o desenho de transição é grave.
Quando o layout da gaveta aparece, o layout da gaveta é opaco, o que significa que o layout do conteúdo atrás do layout da gaveta não precisa ser desenhado, mas o NetEase Cloud o desenha, fazendo com que os pixels na área onde o layout da gaveta está localizado sejam desenhado várias vezes.
O Google tem oficialmente a classe DrawerLayout.Java no pacote android.support.v4.widget. Usado para implementar o layout da gaveta. Esta classe substitui o método drawChild:
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
final int height = getHeight();
// 判断是否是内容视图
final boolean drawingContent = isContentView(child);
int clipLeft = 0, clipRight = getWidth();
// 记录当前画布信息
final int restoreCount = canvas.save();
if (drawingContent) {
// 只有在绘制内容视图时才进行裁切
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View v = getChildAt(i);
if (v == child || v.getVisibility() != VISIBLE ||
!hasOpaqueBackground(v) || !isDrawerView(v) ||
v.getHeight() < height) {
// 如果child是内容视图/视图不可见/视图背景透明/不是抽屉视图/child高度小于父布局高度
// 则不做画布裁切
continue;
}
if (checkDrawerViewAbsoluteGravity(v, Gravity.LEFT)) {
// 盒子在左侧时裁切的left和right
final int vright = v.getRight();
if (vright > clipLeft) clipLeft = vright;
} else {
// 盒子在右侧时裁切的的left和right
final int vleft = v.getLeft();
if (vleft < clipRight) clipRight = vleft;
}
}
// 裁切画布
canvas.clipRect(clipLeft, 0, clipRight, getHeight());
}
// 绘制子视图
final boolean result = super.drawChild(canvas, child, drawingTime);
// 回复到裁切之前的画布
canvas.restoreToCount(restoreCount);
}
O método drawChild é chamado no método dispatchDraw da classe ViewGroup para desenhar subviews. A classe DrawerLayout reescreve este método porque o método drawChild é chamado antes de todas as views filhas serem desenhadas, mas aqui somente a view da área de conteúdo precisa ser cortada. Ao desenhar a visualização da área de conteúdo, obtenha as informações de posição da visualização da gaveta. Se a visualização da gaveta estiver visível, o plano de fundo for opaco e a altura da gaveta for consistente com a altura do layout pai, obtenha as informações de posição à esquerda, bordas superior, direita e inferior da visualização da gaveta na tela. Em seguida, corte, recorte a parte da exibição de conteúdo que não está bloqueada e entregue a tela cortada à exibição filha para desenho, de modo que a área de conteúdo seja desenhada apenas na área de corte e outras áreas não sejam desenhadas empate.
Depois que a sub-View for desenhada, restaure o Canvas para o estado anterior ao corte, porque todas as Views sob uma janela usam o mesmo Canvas, então é necessário restaurar o estado para outras sub-Views usarem.
Vejamos o APP "download" em um sistema, que é implementado pelo DrawerLayout:
Embora a área de conteúdo esteja vermelha no aplicativo, depois que a visualização da gaveta é retirada, o desenho de transição da visualização da gaveta é menor do que a parte desobstruída da área de conteúdo.
3. Plano de fundo de ImageView e sobreposição de imageDrawable
No Android, todas as visualizações podem definir o plano de fundo. Além de definir o plano de fundo, ImageView também pode definir ImageDrawable.
No desenvolvimento, muitas vezes é necessário exibir uma imagem. Antes de carregar a imagem, geralmente é necessário exibir uma imagem padrão. Em muitos casos, a propriedade background de ImageView é usada para definir a imagem de fundo padrão e imageDrawable é usado para definir a imagem a ser carregada. Isso causará um problema: quando a imagem é carregada na página, a imagem de fundo padrão é bloqueada, mas ainda precisa ser desenhada, resultando em um desenho de transição.
A solução é definir a imagem de fundo e a imagem realmente carregada por meio do método imageDrawable .
4. Resumo
-
Uma janela no Android corresponde a um Canvas, e todas as visualizações (View/ViewGroup) sob a janela usam a mesma tela, e o nó pai da árvore de visualização cortará o Canvas antes de chamar o View.draw da subvisualização. A área é a área retangular ocupada pela View na tela, razão pela qual o conteúdo além da borda da View será cortado.
-
Como um pixel do valor do desenho de transição é desenhado várias vezes, precisamos apenas garantir que as imagens ou cores de fundo não se sobreponham. A forma correta deve ser minimizar a área de sobreposição da View com o fundo. Se houver sobreposição, use o clipRect da tela para recortar.
-
Minimize a profundidade da exibição para reduzir o processo de passagem da árvore de exibição.
afinal
Por fim, quero dizer: Para os programadores, existem muitos conteúdos de conhecimento e tecnologias para aprender. Se você não quer ser eliminado pelo ambiente, precisa se aprimorar constantemente. Sempre nos adaptamos ao ambiente, não ao ambiente para se adaptar a nós. !
Para ajudar todos a entender melhor a otimização de desempenho de maneira abrangente e clara, preparamos notas básicas relevantes (retornando à lógica subjacente):https://qr18.cn/FVlo89
Notas básicas de otimização de desempenho:https://qr18.cn/FVlo89
Otimização de inicialização
Otimização de memória Otimização
de interface do usuário
Otimização de rede
Otimização de bitmap e otimização de compressão de imagem : Otimização de simultaneidade multi-thread e otimização de eficiência de transmissão de dados Otimização de pacote de volumehttps://qr18.cn/FVlo89
"Estrutura de monitoramento de desempenho do Android":https://qr18.cn/FVlo89
"Manual de aprendizado do Android Framework":https://qr18.cn/AQpN4J
- Processo de inicialização de inicialização
- Inicie o processo Zygote na inicialização
- Inicie o processo do SystemServer na inicialização
- driver de fichário
- Processo de inicialização do AMS
- O processo de inicialização do PMS
- Processo de inicialização do iniciador
- Os quatro principais componentes do Android
- Serviço do sistema Android - processo de distribuição do evento de entrada
- Análise de código-fonte do mecanismo de atualização de tela de renderização subjacente do Android
- Análise de código-fonte do Android na prática