Otimização de desempenho para desenvolvimento Android: solução de desenho de transição

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:

imagem.png

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

  1. Processo de inicialização de inicialização
  2. Inicie o processo Zygote na inicialização
  3. Inicie o processo do SystemServer na inicialização
  4. driver de fichário
  5. Processo de inicialização do AMS
  6. O processo de inicialização do PMS
  7. Processo de inicialização do iniciador
  8. Os quatro principais componentes do Android
  9. Serviço do sistema Android - processo de distribuição do evento de entrada
  10. Análise de código-fonte do mecanismo de atualização de tela de renderização subjacente do Android
  11. Análise de código-fonte do Android na prática

Acho que você gosta

Origin blog.csdn.net/weixin_61845324/article/details/132351467
Recomendado
Clasificación