Noções básicas sobre os conceitos de tela e superfície

114

Estou lutando para entender o processo de desenho SurfaceViewe, portanto, todo o sistema Surface/ Canvas/ Bitmap, que é usado no Android.

Eu li todos os artigos e páginas de documentação da API, que consegui encontrar no site de desenvolvedores do Android, alguns tutoriais de gráficos do Android, código-fonte do LunarLander e esta questão .

Diga-me quais dessas afirmações são verdadeiras, quais não são e por quê.

  1. Canvastem seu próprio Bitmapanexo a ele. Surfacetem seu próprio Canvasanexo a ele.
  2. Todas Viewas janelas compartilham o mesmo Surfacee, portanto, compartilham o mesmo Canvas.
  3. SurfaceViewé uma subclasse de View, que, ao contrário Viewdas subclasses de outras e de Viewsi mesma, tem seus próprios elementos Surfacepara se inserir.

Há também uma pergunta adicional:

  • Por que há necessidade de uma Surfaceclasse, se já existe um Canvaspara operações de alto nível com bitmap. Dê um exemplo de uma situação em que Canvasnão seja adequado para fazer o trabalho que Surfacepode fazer.
Fiodoraniev
fonte
2
Documento de
fadden

Respostas:

223

Aqui estão algumas definições:

  • Uma superfície é um objeto que contém pixels que estão sendo compostos na tela. Cada janela que você vê na tela (uma caixa de diálogo, sua atividade em tela inteira, a barra de status) tem sua própria superfície para a qual é desenhada e o Surface Flinger as renderiza para a exibição final em sua ordem Z correta. Uma superfície normalmente tem mais de um buffer (geralmente dois) para fazer a renderização em buffer duplo: o aplicativo pode desenhar seu próximo estado de IU enquanto o defletor de superfície está compondo a tela usando o último buffer, sem precisar esperar que o aplicativo termine desenhando.

  • Uma janela é basicamente como você pensa em uma janela na área de trabalho. Possui uma única superfície na qual o conteúdo da janela é renderizado. Um aplicativo interage com o Gerenciador de janelas para criar janelas; o Window Manager cria uma superfície para cada janela e a entrega ao aplicativo para desenho. O aplicativo pode desenhar o que quiser na Superfície; para o gerenciador de janelas é apenas um retângulo opaco.

  • Uma visualização é um elemento de interface do usuário interativo dentro de uma janela. Uma janela possui uma única hierarquia de visualização anexada a ela, que fornece todo o comportamento da janela. Sempre que a janela precisar ser redesenhada (por exemplo, porque uma visualização se invalidou), isso é feito na superfície da janela. A superfície está bloqueada, o que retorna uma tela que pode ser usada para desenhar nela. Uma passagem de desenho é feita na hierarquia, entregando o Canvas para cada visualização para desenhar sua parte da IU. Uma vez feito isso, o Surface é desbloqueado e postado de forma que o buffer recém-desenhado seja trocado para o primeiro plano para então ser composto na tela pelo Surface Flinger.

  • Um SurfaceView é uma implementação especial de View que também cria sua própria Surface dedicada para o aplicativo desenhar diretamente (fora da hierarquia de view normal, que de outra forma deve compartilhar a única Surface para a janela). A maneira como isso funciona é mais simples do que você pode esperar - tudo o que SurfaceView faz é pedir ao gerenciador de janelas para criar uma nova janela, dizendo-lhe para ordenar a janela imediatamente atrás ou na frente da janela do SurfaceView, e posicionando-a para corresponder onde o SurfaceView aparece na janela que o contém. Se a superfície está sendo colocada atrás da janela principal (na ordem Z), SurfaceView também preenche sua parte da janela principal com transparência para que a superfície possa ser vista.

  • Um bitmap é apenas uma interface para alguns dados de pixel. Os pixels podem ser alocados pelo próprio Bitmap quando você está criando um diretamente, ou pode estar apontando para pixels que não possui, como o que acontece internamente para conectar um Canvas a uma Surface para desenhar. (Um bitmap é criado e apontado para o buffer de desenho atual da superfície.)

Além disso, lembre-se de que, como isso implica, um SurfaceView é um objeto muito pesado. Se você tiver vários SurfaceViews em uma IU específica, pare e pense se isso é realmente necessário. Se você tiver mais de dois, quase certamente terá muitos.

hackbod
fonte
Muito obrigado! A resposta tornou as coisas mais claras. No entanto, a parte sobre como conectar o Canvas ao Surface não está clara. Não consigo imaginar onde essa operação é necessária. Pode ser o próximo exemplo dessa operação: desenho de bitmap em uma tela, adquirido de SurfaceHolder com o método lockCanvas ()?
fyodorananiev
1
É assim que o desenho acontece. Canvas é a API de desenho 2D. Se você for desenhar em uma superfície, precisará fazer um Canvas que aponte para seu buffer para usar a API de desenho do Canvas 2d para desenhar nele.
hackbod
6
Além de #hackbod'sresponder, SurfaceViewtambém pode ser renderizado a partir de thread secundário, o que não é possível para Viewobjetos
Mohanraj Balasubramaniam
47

Uma visão geral conceitual de Window, Surface, Canvas e Bitmap

Aqui está uma visão geral conceitual muito básica e simples de como a interação acontece entre a janela, superfície, tela e bitmap.
Às vezes, uma representação visual ajuda muito na compreensão de conceitos distorcidos.
Espero que este gráfico possa ajudar alguém.

Sabeeh
fonte
4
Imagens visuais são melhores do que texto: D
Maveň ツ
18

Um bitmap é simplesmente um invólucro para uma coleção de pixels. Pense nisso como uma matriz de pixels com algumas outras funções convenientes.

O Canvas é simplesmente a classe que contém todos os métodos de desenho. É semelhante à classe Graphics em AWT / Swing se você estiver familiarizado com ela. Toda a lógica de como desenhar um círculo, ou uma caixa, etc. está contida no Canvas. Uma tela desenha em um bitmap ou um contêiner GL aberto, mas não há razão para que no futuro ela possa ser estendida para desenhar em outros tipos de rasters.

SurfaceView é uma vista que contém uma superfície. Uma superfície é semelhante a um bitmap (tem um armazenamento de pixels). Não sei como é implementado, mas imagino que seja algum tipo de invólucro de bitmap com métodos extras para coisas que estão diretamente relacionadas a exibições de tela (essa é a razão para uma superfície, um bitmap é muito genérico). Você pode obter uma tela de sua superfície que está realmente obtendo a tela associada ao bitmap subjacente.

Suas perguntas.

1.Canvas tem seu próprio bitmap anexado a ele. O Surface tem seu próprio Canvas anexado a ele.

Sim, uma tela opera em um bitmap (ou um painel GL aberto). O Surface fornece um Canvas que opera em qualquer superfície que esteja usando para seu armazenamento de pixels de estilo Bitmap.

2. Todas as visualizações da janela compartilham a mesma superfície e, portanto, compartilham a mesma tela.

Não. Você pode ter quantas visualizações de superfície quiser.

3.SurfaceView é uma subclasse de View, que, ao contrário de outras subclasses de View e da própria View, tem sua própria Surface para desenhar.

Sim. Assim como ListView é uma subclasse de View que possui sua própria estrutura de dados List. Cada subclasse de View faz algo diferente.

sksamuel
fonte
1
Então, Bitmape Surfacesão apenas espécies diferentes de armazenamento de pixels e Canvaspodem envolver qualquer um deles?
fyodorananiev
2
Basicamente sim. Exceto que o Canvas não pode gravar em uma superfície, ele opera em qualquer superfície que esteja usando como seu próprio armazenamento de pixels (sem olhar para a fonte do Android, não posso dizer com certeza o que é). Provavelmente é algum tipo de extensão de Bitmap, já que o Canvas fornece apenas construtores para Bitmap e GL.
sksamuel
Ótima ajuda, obrigado! Sobre a resposta 2. Na minha pergunta, quis dizer visualizações padrão, não SurfaceViews. Suponha que eu tenha RelativeLayout com muitos campos e botões. Nesse caso, Surface anexado a toda a janela e compartilhado por todas as visualizações na hierarquia de visualizações?
fyodorananiev
1
Lembre-se de que o Surface é apenas uma coleção de pixels. Portanto, cada visualização de superfície tem sua própria superfície e cada uma pode ser renderizada em uma parte diferente da tela. Eles não necessariamente preenchem a tela (embora esse seja o uso comum, para renderizar gráficos em um jogo em tela inteira).
sksamuel
1
Eu realmente não pensaria em Bitmap e Surface como equivalentes. Uma superfície é um objeto que o defletor de superfície, o compositor da janela, conhece. Ou seja, é algo diretamente visível na tela, tem uma ordem Z na tela, etc.
hackbod