Flutter sob o capô: ligação

Este artigo é uma continuação direta do meu artigo anterior .



Para uma percepção completa, aconselho que primeiro leia o artigo indicado no link ou atualize-o na memória. Nele, analisei um dos aspectos importantes do dispositivo Flutter - a interação das árvores e a distribuição de responsabilidade entre elas. No entanto, a questão permanece em aberto: como é organizado o funcionamento de todo o mecanismo descrito na primeira parte? Isso é o que tentaremos entender neste artigo.







Disposições Gerais



Se você abrir a visão geral técnica do Flutter , em um dos pontos veremos o diagrama a seguir. Mostra os níveis condicionais em que os próprios autores da estrutura o dividem. 



Esquema de estrutura de flutuação


Na verdade, como eles próprios chamam, vemos um bolo folhado. Camadas maiores e menores podem ser distinguidas.



O nível de estrutura é tudo com que trabalhamos no momento de escrever o aplicativo e todas as classes de utilitários que nos permitem interagir com o nível de mecanismo que escrevemos. Tudo relacionado a este nível está escrito em Dart.



Nível de mecanismo - um nível inferior ao nível de estrutura, contém classes e bibliotecas que permitem que o nível de estrutura funcione. Inclui máquina virtual Dart, Skia, etc.



Nível de plataforma - mecanismos específicos de plataforma  específicos para uma plataforma de lançamento particular.



Vamos dar uma olhada mais de perto no nível da estrutura. No diagrama, ele é representado na forma de camadas de nível superior para nível inferior. Bem na parte inferior, vemos uma camadaFundação . Como o nome sugere, essa camada é algo fundamental e básico no nível do framework. Encontramos essa biblioteca e isso é o que está escrito em sua descrição:



Primitivas do framework Core Flutter.

Os recursos definidos nesta biblioteca são as classes e funções de utilitário de nível mais baixo usadas por todas as outras camadas da estrutura Flutter.




As funções definidas nesta biblioteca são as classes de utilitário e as funções de nível mais baixo usadas por todas as outras camadas da estrutura do Flutter.



Essa biblioteca também contém o BindingBase - a classe base para todos os Binding.



Obrigatório



Primeiro, vamos entender o que é Binding e como o Flutter o usa. O próprio nome nos diz que se trata de algum tipo de conexão. A documentação deixada pelo comando Flutter para BaseBinding nos diz o seguinte:



Classe base para mixins que fornecem serviços singleton (também conhecidos como "bindings"). Para usar esta classe em uma cláusula `on` de um mixin, herde dela e implemente [initInstances ()]. O mixin é garantido para ser construído apenas uma vez durante a vida útil do aplicativo (mais precisamente, ele será declarado se construído duas vezes no modo marcado).



Esta é a classe base para vários serviços de comunicação, que são apresentados como mixins. Cada um desses mixin é inicializado e garante a exclusividade de sua instância durante a vida útil do aplicativo.



BaseBindingÉ uma classe abstrata base, vamos então examinar as implementações concretas de ligações. Entre eles veremos:



ServicesBinding é responsável por encaminhar mensagens da plataforma atual para o manipulador de dados de mensagem (BinaryMessenger);



PaintingBinding é responsável pela comunicação com a biblioteca de renderização.



O RenderBinding é responsável pela comunicação entre a árvore de renderização e o mecanismo Flutter.



WidgetBinding é responsável pela comunicação entre a árvore de widgets e o mecanismo Flutter.



SchedulerBinding - o programador das próximas tarefas, como:



  • chamadas para chamadas de retorno que o sistema inicia em Window.onBeginFrame - por exemplo, eventos para tickers e controladores de animação;
  • chamadas para retornos de chamada contínuos que o sistema Window.onDrawFrame inicia, por exemplo, eventos para atualizar o sistema de exibição após os retornos de chamada de entrada serem concluídos;
  • retornos de chamada pós-quadro, que são chamados após retornos de chamada contínuos, antes de retornar de Window.onDrawFrame;
  • tarefas de não renderização que devem ser realizadas entre os quadros.


SemanticsBinding é responsável por conectar a camada semântica e o mecanismo Flutter.



GestureBinding é responsável por trabalhar com o subsistema de gestos.



Como o nome sugere, as ligações são uma camada de comunicação entre o nível do mecanismo Flutter e o nível da estrutura em si, cada um dos quais é responsável por uma direção específica de trabalho.



WidgetsFlutterBinding



Para entender melhor como tudo funciona junto, vamos dar uma olhada no lugar que é o ponto de partida para qualquer aplicativo Flutter - a chamada runApp. O método que estamos chamando está no arquivo binding.dart e isso não é coincidência. A descrição dele diz que ele expande o widget do aplicativo passado e o anexa à tela. Vamos ver o que faz:



void runApp(Widget app) {
  WidgetsFlutterBinding.ensureInitialized()
    ..scheduleAttachRootWidget(app)
    ..scheduleWarmUpFrame();
}


É aqui que encontramos WidgetsFlutterBinding - uma implementação concreta de uma ligação de aplicativo baseada em uma estrutura de widget. Em seu núcleo, é a cola que mantém a estrutura do Flutter e o mecanismo juntos. O WidgetsFlutterBinding consiste em muitas das ligações que discutimos anteriormente: GestureBinding , ServicesBinding , SchedulerBinding , PaintingBinding , SemanticsBinding , RendererBinding , WidgetsBinding . Assim, obtivemos uma camada que pode conectar nosso aplicativo em todas as direções necessárias com o mecanismo Flutter.



Vamos voltar ao lançamento do aplicativo. Em WidgetsFlutterBindingos scheduleAttachRootWidget e scheduleWarmUpFrame métodos são chamados , vamos ver o que acontece nelas.



ScheduleAttachRootWidget



O método scheduleAttachRootWidget é uma implementação adiada de attachRootWidget. Este método pertence a WidgetsBinding . A descrição dele diz que ele anexa o widget passado a renderViewElement - o elemento raiz da árvore de elementos. 



void attachRootWidget(Widget rootWidget) {
    _renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
      container: renderView,
      debugShortDescription: '[root]',
      child: rootWidget,
    ).attachToRenderTree(buildOwner, renderViewElement);
}


A partir do código, podemos ver que este método cria o RenderObjectToWidgetAdapter, que é o widget raiz da árvore de widgets e é usado como uma ponte conectando as árvores umas às outras. Olhando para sua implementação, veremos que ele não cria um RenderObject para si mesmo, mas retorna um valor do campo do contêiner, e passamos renderView do RendererBinding para ele quando o criamos. Este renderView é o elemento raiz da árvore de renderização.



RenderView get renderView => _pipelineOwner.rootNode;



O PipelineOwner é na verdade o gerenciador que gerencia o processo de renderização.



De volta ao método attachRootWidget... O método attachToRenderTree é chamado no adaptador criado, com o qual criamos a raiz da árvore de elementos pela primeira vez. Deve-se observar que o buildOwner é passado para o método attachToRenderTree . Esta classe é um gerenciador de construção de árvore de widget, que monitora o estado de widgets, monitora a necessidade de atualização e executa uma série de outras tarefas importantes relacionadas à atualização do estado da árvore de widget. Assim, obtemos as três árvores Flutter, cada uma delas armazenada e gerenciada por meio de Bindings.



ScheduleWarmUpFrame



O método scheduleWarmUpFrame pertence a SchedulerBinding e é usado para agendar um quadro para iniciar o mais rápido possível, sem esperar pelo sinal do sistema "Vsync". Como o método é usado durante a inicialização do aplicativo, o primeiro quadro, que provavelmente será bem caro, levará algum tempo extra para disparar. Este método bloqueia o envio de eventos até a conclusão do quadro programado.



Como podemos ver, ambos os mecanismos lançados na inicialização se relacionam e interagem com vários Bindings, que por sua vez estão intimamente relacionados e fornecem interação com o sistema. Vamos resumir com o diagrama a seguir.







Conclusão



As vinculações são um mecanismo importante para organizar um aplicativo Flutter. É ele quem conecta vários aspectos do aplicativo entre si, bem como com o motor.



Inclusive graças a ele, podemos escrever nossa aplicação na parte de mais alto nível do framework, sem nos preocupar em como organizamos o trabalho coerente de todo o resto. Espero que este artigo ajude você a entender essa parte do dispositivo Flutter.



Obrigado pela atenção!



Materiais utilizados:



Flutter

https://flutter.dev/



All Articles