The concept of life cycle

  1. What is the life cycle?

Lifecycle is basically a method function called back to let developers know what state the Widget is in

  1. What does it do?
  • Listen for events in widgets
  • Initializing data: Creating data and sending network requests
  • Memory management: destroy data and listeners, destroy timers, etc

The Widget’s life cycle

  1. statelessStateless
    • A constructor
    • The build method
class SearchCell extends StatelessWidget {
 // const SearchCell();
  SearchCell(){
    print('Constructor called');
  };
  
  @override
  Widget build(BuildContext context) {
    print('Build method called');
    return Container();
}
Copy the code

  1. statefulStatefulContains two objectsWidget,State)
    • Constructor of a Widget
    • The WidgetcreatState
    • Constructor of State
    • The State ofinitStatemethods
    • didChangeDependenciesMethods: Change the dependency, and the method is called when the InheritedWidget for the dependency (shared data) changes
    • The State ofbuildMethod when calledsetStateMethod, which recalls build to render
    • The State ofdisposeMethod, called at destruction time
class SearchPage extends StatefulWidget {
  SearchPage(){
    print('Widget constructor ');
  }

  @override
  _SearchPageState createState() {
    print('the Widget CreatState');
    return_SearchPageState(); }}class _SearchPageState extends State<SearchPage> {
  _SearchPageState() {
    print('Constructor of State');
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    print('State's initState method ');
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    print(Dispose method of State);
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    print('didChangeDependencies methods');
  }
  
   @override
  Widget build(BuildContext context) {
    print('State build method ');
    returnContainer(); }}Copy the code

Use the Flutter Hot Restart

Use a Flutter Hot Reload

  1. setStateInside the method:

_elementThe type of:StatefulElement? _element;

  BuildContext get context {
    assert(() {
      if (_element == null) {
        throw FlutterError(
          'This widget has been unmounted, so the State no longer has a context (and should be considered defunct). \n'
          'Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.',); }return true; } ());return_element! ; } StatefulElement? _element;Copy the code

We can see that the _element is the current context, so this is why calling setState reconstructs the build.

context as StatefulElement;
context.markNeedsBuild();
Copy the code

The above two lines of code have the same effect as setState!

  1. InheritedWidgetData sharing

If data from A needs to be passed to B, we passed it in the constructor, and the didChangeDependencies method is called only once in the following example.

class InheritedDemo extends StatefulWidget {
  const InheritedDemo({Key? key}) : super(key: key);

  @override
  _InheritedDemoState createState() => _InheritedDemoState();
}

class _InheritedDemoState extends State<InheritedDemo> {
  int _count = 0;@override
  Widget build(BuildContext context) {
    return Column(
      children: [
        SizedBox(height: 200),
        TextCount(count: _count),// _count is passed through the component's constructor
        ElevatedButton(
          onPressed: () {
            _count++;
            setState(() {});
          },
          child: Text('am I'), a)],); }}class TextCount extends StatefulWidget {
  final int count;
  TextCount({required this.count});

  @override
  _TextCountState createState() => _TextCountState();
}

class _TextCountState extends State<TextCount> {
  @override
  Widget build(BuildContext context) {
    returnText(widget.count.toString()); }}Copy the code

[InheritedWidget] [InheritedWidget] [InheritedWidget] [InheritedWidget] [InheritedWidget] [InheritedWidget] [InheritedWidget] [InheritedWidget]

abstract class InheritedWidget extends ProxyWidget {
  // The constructor of the parent class
  const InheritedWidget({ Key? key, required Widget child })
    : super(key: key, child: child);
  
  @override
  InheritedElement createElement() => InheritedElement(this);
	
  @protected
  bool updateShouldNotify(covariant InheritedWidget oldWidget);
}
Copy the code
    • Start by defining a shared data class that inherits from the widget
    • Secondly, implement the constructor, which can be referred toInheritedWidgetAbstract the methods of the base class
    • Finally, define a class method for external use to easily retrieve data
    • Also choose to implement update data to notify widgets that rely on shared data
class MyData extends InheritedWidget {
  final int count;
  // constructor
  const MyData({required this.count, required Widget child})
      : super(child: child);
  // Class methods are provided for external use to retrieve data
  static MyData? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<MyData>();
  }

// Whether to notify when data changes
  @override
  bool updateShouldNotify(MyData oldWidget) {
    return oldWidget.count != count;
  }
}
Copy the code

So how do you use it to associate data with components?

    • Save and associate: Use the constructor in the build method to retrieve the data saved and associated with widgets that need to use that data
    • Pull out: Call the class method to pull out the widget when it needs to be used
class _InheritedDemoState extends State<InheritedDemo> {
  int _count = 0;
  @override
  Widget build(BuildContext context) {
    return MyData( // Use it here
        count: _count,
        child: ....
    );
  }
}

class _TextCountState extends State<TextCount> {
  @override
  Widget build(BuildContext context) {
    returnText(MyData.of(context)! .count.toString()); }@override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    print('didChangeDependencies methods'); }}Copy the code

The didChangeDependencies method is called again every time you click on it

How widgets render

Not all of themWidgetWill be rendered independently! Only integratedRenderObjectWidgetWill be createdRenderObjectObject! inFlutterIn the rendering process, there are three important trees,FlutterThe engine is aimed atRenderTree render!

  1. Widget tree, Element tree, Render Tree: Each Widget creates an Element object. The creatElement method is implicitly called to add Element to the Element tree

    • RenderElement
    • StatefulElement
    • StatelessElement
  2. RenderElement: Basically create a RenderObject (RenderObjectWidget widgets create RenderElement)

    • FluterWill be calledmountMethod to createRanderObjectobject
  3. StatefulElement inherits ComponentElement(StatefulWidget creates StatefulElement)

    • Call the creatState method to create the State
    • Assign the Widget to statestate._widget = widget;
    • Call state’s build method and pass Element, which is itself

  1. StatelessElementInherited:ComponentElement(StatelessWidgetWill createStatelessElement)
    • Stateless creates Element
    • The Element creation then calls the mount method
    • Mount calls the widget’s bulid method to render and passes the Element itself