Flutter sous le capot: Reliure

Cet article est une continuation directe de mon article précédent .



Pour une perception complète, je vous conseille de lire d'abord l'article indiqué sur le lien ou de le rafraîchir dans votre mémoire. J'y ai analysé l'un des aspects importants du dispositif Flutter - l'interaction des arbres et la répartition des responsabilités entre eux. Cependant, la question reste ouverte: comment s'organise le fonctionnement de l'ensemble du mécanisme décrit dans la première partie? C'est ce que nous allons essayer de comprendre dans cet article.







Dispositions générales



Si vous ouvrez la présentation technique de Flutter , dans l'un des points, nous verrons le diagramme suivant. Il montre les niveaux conditionnels dans lesquels les auteurs du cadre le divisent eux-mêmes. 



Schéma de cadre Flutter


En fait, comme ils l'appelaient eux-mêmes, nous voyons un gâteau feuilleté. Des couches plus grandes et plus petites peuvent être distinguées.



Le niveau du framework est tout ce avec quoi nous travaillons au moment de l'écriture de l'application, et toutes les classes d'utilité qui nous permettent d'interagir avec le niveau de moteur que nous avons écrit. Tout ce qui concerne ce niveau est écrit en Dart.



Niveau du moteur - un niveau inférieur au niveau du cadre, contient des classes et des bibliothèques qui permettent au niveau du cadre de fonctionner. Y compris la machine virtuelle Dart, Skia, etc.



Couche de plate-forme -  Mécanismes spécifiques à la plate-forme spécifiques à la plate-forme de lancement.



Examinons de plus près le niveau du cadre. Dans le diagramme, il est représenté sous la forme de couches allant du niveau supérieur au niveau bas. Tout en bas, nous voyons une coucheFondation . Comme son nom l'indique, cette couche est quelque chose de fondamental et de base au niveau du cadre. On retrouve cette librairie et c'est ce qui est écrit dans sa description:



Primitives du framework Core Flutter.

Les fonctionnalités définies dans cette bibliothèque sont les classes et fonctions utilitaires de plus bas niveau utilisées par toutes les autres couches du framework Flutter.




Les fonctions définies dans cette bibliothèque sont les classes d'utilité et les fonctions de niveau le plus bas utilisées par toutes les autres couches du framework Flutter.



Cette bibliothèque contient également la BindingBase - la classe de base pour toutes les liaisons .



Contraignant



Tout d'abord, comprenons ce qu'est la liaison et comment elle est utilisée dans Flutter. Le nom lui-même nous dit qu'il s'agit d'une sorte de connexion. La documentation laissée par la commande Flutter à BaseBinding nous dit ce qui suit:



Classe de base pour les mixins qui fournissent des services singleton (également appelés "bindings"). Pour utiliser cette classe dans une clause `on` d'un mixin, héritez-en et implémentez [initInstances ()]. Il est garanti que le mixin ne sera construit qu'une fois dans la vie de l'application (plus précisément, il affirmera s'il est construit deux fois en mode vérifié).



Il s'agit de la classe de base pour divers services de communication, qui sont présentés sous forme de mixins. Chacun de ces mixin est initialisé et garantit l'unicité de son instance pendant la durée de vie de l'application.



BaseBindingEst une classe abstraite de base, regardons ensuite les implémentations concrètes des liaisons. Parmi eux, nous verrons:



ServicesBinding est responsable de la transmission des messages de la plate-forme actuelle vers le gestionnaire de données de message (BinaryMessenger);



PaintingBinding est responsable de la communication avec la bibliothèque de rendu.



Le RenderBinding est responsable de la communication entre l'arborescence de rendu et le moteur Flutter.



WidgetBinding est responsable de la communication entre l'arborescence des widgets et le moteur Flutter.



SchedulerBinding est un planificateur pour les tâches régulières, telles que:



  • les appels aux rappels entrants que le système lance dans Window.onBeginFrame - par exemple, les événements de ticker et de contrôleur d'animation;
  • des appels à des rappels continus que le système Window.onDrawFrame lance, par exemple, des événements pour mettre à jour le système d'affichage une fois les rappels entrants terminés;
  • les rappels post-frame, qui sont appelés après des rappels continus, avant de revenir de Window.onDrawFrame;
  • les tâches sans rendu qui doivent être effectuées entre les images.


SemanticsBinding est responsable de la connexion de la couche sémantique et du moteur Flutter.



GestureBinding est chargé de travailler avec le sous-système de gestes.



Comme son nom l'indique, les liaisons sont une couche de communication entre le niveau du moteur Flutter et le niveau du framework lui-même, chacun étant responsable d'une direction de travail spécifique.



WidgetsFlutterBinding



Pour mieux comprendre comment tout cela fonctionne ensemble, regardons l'endroit qui est le point de départ de toute application Flutter - l'appel à runApp. La méthode que nous appelons se trouve dans le fichier binding.dart et ce n'est pas un hasard. La description de celui-ci indique qu'il étend le widget d'application passé et le joint à l'écran. Voyons ce que ça fait:



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


C'est là que nous rencontrons WidgetsFlutterBinding - une implémentation concrète d'une liaison d'application basée sur un framework de widget. À la base, c'est la colle qui maintient ensemble le cadre Flutter et le moteur. WidgetsFlutterBinding se compose de plusieurs des liaisons dont nous avons parlé précédemment: GestureBinding , ServicesBinding , SchedulerBinding , PaintingBinding , SemanticsBinding , RendererBinding , WidgetsBinding . Ainsi, nous avons une couche qui peut connecter notre application dans toutes les directions nécessaires avec le moteur Flutter.



Revenons au lancement de l'application. Dans WidgetsFlutterBindingles méthodes scheduleAttachRootWidget et scheduleWarmUpFrame sont appelées , voyons ce qui s'y passe.



ScheduleAttachRootWidget



La méthode scheduleAttachRootWidget est une implémentation différée de attachRootWidget. Cette méthode appartient à WidgetsBinding . La description de celui-ci dit qu'il attache le widget passé à renderViewElement - l'élément racine de l'arborescence d'éléments. 



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


À partir du code, nous pouvons voir que cette méthode crée le RenderObjectToWidgetAdapter, qui est le widget racine de l'arborescence des widgets et est utilisé comme un pont reliant les arbres les uns aux autres. En regardant son implémentation, nous verrons qu'il ne crée pas un RenderObject pour lui-même, mais renvoie une valeur à partir du champ conteneur, et nous lui passons le renderView de RendererBinding lorsque nous le créons. Ce renderView est l'élément racine de l'arborescence de rendu.



RenderView get renderView => _pipelineOwner.rootNode;



PipelineOwner est en fait le gestionnaire qui gère le processus de rendu.



Retour à la méthode attachRootWidget... La méthode attachToRenderTree est appelée sur l'adaptateur créé, avec lequel nous créons la racine de l'arborescence d'éléments pour la première fois. Notez que buildOwner est passé à la méthode attachToRenderTree . Cette classe est un gestionnaire de construction d'arborescence de widgets qui surveille l'état des widgets, surveille le besoin de mises à jour et effectue un certain nombre d'autres tâches importantes liées à la mise à jour de l'état de l'arborescence des widgets. Ainsi, nous obtenons les trois arbres Flutter, dont chacun est stocké et géré via des liaisons.



CalendrierWarmUpFrame



La méthode scheduleWarmUpFrame appartient à SchedulerBinding et est utilisée pour planifier une trame à exécuter dès que possible sans attendre le signal système "Vsync". Étant donné que la méthode est utilisée lors du démarrage de l'application, la première image, qui est probablement assez coûteuse, prendra un certain temps à se déclencher. Cette méthode bloque l'envoi d'événements jusqu'à la fin de la trame planifiée.



Comme nous pouvons le voir, les deux mécanismes lancés au démarrage sont liés et interagissent avec diverses liaisons, qui à leur tour sont étroitement liées et fournissent une interaction avec le système. Résumons avec le diagramme suivant.







Conclusion



Les liaisons sont un mécanisme important pour organiser une application Flutter. C'est lui qui connecte différents aspects de l'application entre eux, ainsi qu'avec le moteur.



Y compris grâce à lui, nous pouvons écrire notre application au plus haut niveau du framework, sans nous soucier de la façon dont nous organisons le travail cohérent de tout le reste. J'espère que cet article vous aidera à comprendre cette partie de l'appareil Flutter.



Merci de votre attention!



Les matériaux utilisés:



Flutter

https://flutter.dev/



All Articles