Colección de citas famosas - Slogan de motivación - Gestión del estado de Flutter Análisis del principio del widget heredado

Gestión del estado de Flutter Análisis del principio del widget heredado

Demostración de un artículo escrito recientemente por la empresa para compartir tecnología

Gestión del estado de InheritedWidget en Flutter

1 ¿Qué es InheritedWidget?

InheritedWidget es un componente funcional muy importante en Flutter. Proporciona una forma de pasar y compartir datos de arriba a abajo en el árbol de widgets. Por ejemplo, en el widget raíz de nuestra aplicación. datos a través de InheritedWidget, podemos obtener los datos compartidos en cualquier sub-widget. ¡Esta característica es muy conveniente en algunos escenarios donde es necesario compartir datos en el árbol de widgets! Por ejemplo, en el SDK de Flutter, InheritedWidget se usa para compartir información sobre el tema de la aplicación y la configuración regional (configuración regional actual).

InheritedWidget tiene funciones similares al contexto en React. En comparación con el paso de datos paso a paso, pueden realizar una transferencia de datos entre niveles entre componentes. La dirección de transferencia de datos de InheritedWidget en el árbol de widgets es de arriba a abajo, que es exactamente la dirección opuesta a la notificación de notificación.

2. Análisis del código fuente

InheritedWidget

Veamos primero el código fuente de InheritedWidget:

¿clase abstracta?InheritedWidget?extends ?ProxyWidget { ?const?InheritedWidget({ Clave clave,?Widget hijo }):?super(clave: clave,?niño: hijo);?@override?InheritedElement?createElement() =gt;InheritedElement(this);?@ protected?bool ?updateShouldNotify(covariant?InheritedWidget oldWidget);}

Hereda de ProxyWidget:

clase abstracta?ProxyWidget?extends?Widget { ?const?ProxyWidget({ Key key, ?@required ?this.child?}):?super(key: key);?final?Widget?child;}

Se puede ver que no hay otras operaciones en Widget excepto el método createElement Su implementación La clave debe ser InheritedElement.

InheritedElement Echemos un vistazo al código fuente de InheritedElement

class?InheritedElement?extends?ProxyElement { ?InheritedElement(Widget InheritedWidget) :?super(widget);?@override?InheritedWidget ?get?widget ?=gt;?super.widget;?// Este conjunto registra todos los Elementfinal?Maplt;Element,?Objectgt;?_dependents?=?HashMaplt;Element,?Objectgt;(); p> // Este método se llamará en los métodos de montaje y activación del elemento. _inheritedWidgets es un miembro de la clase base Element y se usa para mejorar la eficiencia del widget para encontrar el InheritedWidget en el nodo principal. Utiliza HashMap para almacenar en caché. todos los widgets relacionados en el nodo principal del nodo. InheritedElement, por lo que la complejidad temporal de la búsqueda es o(1) ?@override?void?_updateInheritance() {final?Maplt;Type,?InheritedElementgt; incomingWidgets =?_parent?. _inheritedWidgets;if?(inheritedWidgets!=?null)? _inheritedWidgets?=?HashMaplt;Tipo,?InheritedElementgt;(); ] =?this;?}

// Este método se llama en la clase principal ProxyElement. Puede saber por el nombre que es para notificar a la parte dependiente que es hora de actualizar. Primero se llama al método updateShouldNotify anulado para ver si es necesario actualizarlo, y luego se recorre la lista _dependents y se llama al método didChangeDependencies en este método, por lo que en el siguiente proceso de dibujo del cuadro se llamará el widget correspondiente. reconstruido y la interfaz se actualizará? );}?}

La implementación del método _updateInheritance en la clase base Element es la siguiente:

void _updateInheritance() {

?_inheritedWidgets = _parent ?._inheritedWidgets;

}

En resumen, Element está en moun

En el proceso de t, si no es un InheritedElement, simplemente apunte el caché al caché del nodo principal. Si es un InheritedElement, cree una copia en caché y luego agréguelo a la copia. entonces:

Los nodos principales de InheritedElement no pueden encontrarse a sí mismos, es decir, los datos de InheritedWidget solo se pueden pasar del nodo principal al nodo secundario, y no al revés.

Si el nodo padre de un nodo tiene más de un InheritedWidget del mismo tipo, llamar a heredarFromWidgetOfExactType obtendrá el InheritedWidget de este tipo más cercano a él.

Viendo que parece haber un problema sin resolver aquí, ¿cuándo se agregó el widget que depende de él a la lista _dependientes?

Recuerde el proceso de obtención de datos de InheritedWidget. Existe una convención común para InheritedWidget que consiste en agregar el método estático. En este método, heredarFromWidgetOfExactType se utiliza para encontrar la instancia de InheritedWidget del tipo correspondiente en el archivo. parent y lo devuelve. Al mismo tiempo, también se registra en la lista de dependencias. La implementación de este método se encuentra en la clase Element y se implementa de la siguiente manera:

@overrideT?dependOnInheritedWidgetOfExactType

// Esto se establece mediante el proceso de montaje anterior. La caché HashMap encuentra el InheritedElement del tipo correspondiente final?InheritedElement ancestro =?_inheritedWidgets?==?nullnull?:?_inheritedWidgets[T];if?(ancestor != ?null) {assert(ancestro?is?InheritedElement);return?dependOnInheritedElement (ancestro,?aspecto: aspecto);?}?_hadUnsatisfiedDependencies?=?true;?return null;}

@overrideInheritedWidget?dependOnInheritedElement (Ancestro de InheritedElement,?{ Aspecto del objeto }) {?assert(ancestor ! =?null);

// Esta lista registra todos los elementos heredados de los que depende el elemento actual y se utiliza para eliminarse de la lista _dependientes de InheritedElement cuando el elemento actual se desactiva para evitar actualizaciones innecesarias?_dependencies=?HashSetlt;InheritedElementgt;();?_dependencies.add(ancestor);?ancestor.updateDependencies(this,?aspect);return?ancestor. widget;}

3. Cómo utilizar InheritedWidget

1) Crear una clase que herede de Inheritedwidget

class?InheritedContext?extends?InheritedWidget{?final ?InheritedTestModel?inheritedTestModel;?InheritedContext({Clave clave, @required?this. heredadoTestModel, @required?Widget child}):?super(clave: clave,?niño: hijo); static?InheritedContext de (contexto BuildContext) { return?context.dependOnInheritedWidgetOfExactTyp

elt;InheritedContextgt;();?}?@override?bool?updateShouldNotify(InheritedContext oldWidget) {return?inheritedTestModel?= oldWidget.inheritedTestModel;?}}

2), la clase InheritedTestModel es un contenedor de datos ( Aquí se define una fuente de datos Listlt; intgt;)

class?InheritedTestModel{?final?List?_list;?InheritedTestModel(this._list);?List?getList(){return?_list;?} }

clase?ArrayListData{?static?List? _list; static?List? getListData (){ _list? =?_list(); ; _list .add(3); _list .add(4); return? _list ;?}}

3) Defina un widget utilizando los datos de la clase InheritedContext InheritedTestModel

?ListDemo?extends?StatefulWidget{?@override?State?createState() {return new?ListDemoState();?}}class?ListDemoState?extends?Statelt;ListDemogt;{List?_list;?InheritedTestModel?_inheritedTestModel ?Timer? _timer;?Duración?oneSec?=?const?Duración(segundos:?1);?@override?void?initState() {_list?= ArrayListData.getListData ();_inheritedTestModel?=?new?InheritedTestModel(_list ); ?=?Timer.periodic(oneSec,?(timer) {?_doTimer();});?}?void?_doTimer() {for(int i =?0;?i lt;?_list.length ;?i ){?_list[i] =?_list[i] ?1;}?setState(() {_inheritedTestModel?=?new?InheritedTestModel(_list);?});?}Widget?_buildBody() {return ?Container( niño:?ListDemo2(),);?}?@override?Widget?build(Contexto BuildContext) {return?InheritedContext(inheritedTestModel:?_inheritedTestModel,?child:?Scaffold(appBar:?AppBar(title:?Text ("ListDemo "), acción

ns: lt;Widgetgt;[IconButton(icono:?Icon(Icons.add),)],), cuerpo: _buildBody(),?),);?}?@override?void?dispose() {super.dispose (); if?(_timer?!=?null) {?_timer.cancel();}?}}

4) ¿Actualizar los datos en InheritedTestModel a través de Timer en ListDemo y luego descargar Actualizar? datos en un widget como visualización

class?ListDemo2?extends?StatefulWidget{?@override?State?createState() {return new?ListDemoState2();?}}class?ListDemoState2?extends? ListDemo2gt; {InheritedTestModel?_inheritedTestModel;?Widget?_buildListItem(BuildContext context, int index) {return ?Container(alto:?50, ancho:?100, alineación: Alignment.center, child:?Text(_inheritedTestModel.getList( )[ index].toString());?}Widget?_buildBody() {_inheritedTestModel?= InheritedContext. of (context).inheritedTestModel return?Container(child:?ListView.builder(itemBuilder: (contexto,?index)= gt;_buildListItem(contexto, índice), itemCount:?_inheritedTestModel.getList().length,),);?}?@override?Widget?build(BuildContext context) {return ?_buildBody();?}}< /p >

De esta manera, los datos se pueden actualizar en el widget principal y la Vista secundaria puede obtener directamente los nuevos datos actualizados del contenedor de datos InheritedTestModel sin ninguna operación

¿Estos son datos*? ** Un ejemplo simple de compartir, el proceso básico es aproximadamente que A actualiza los datos de B. A y B tienen la misma clase principal para realizar el intercambio de datos

4 Como se mencionó anteriormente El principio y Se explica el uso básico, pero en proyectos reales, ciertamente no recomiendo usarlo de esta manera. Google ha empaquetado un proveedor de complementos más potente para nosotros. Su principio interno se basa en InheritedWidget. Entendemos el principio básico. utilizar Proveedor en proyectos