online software programming courses

All About Flutter

Flutter is another front end technology. It's a UI framework for mobile developers. With this you write code once and run everywhere. You just need one codebase which saves much more time and resources than building an app using iOS and Android native code.

First, let's see the flutter lifecycle in a complete picture.

What is State?

   Initialization process when a widget has created.

   √ State change during the lifetime of a widget.

State objects are long-lived. They can tell Flutter to repaint, but can also be told to repaint becasue the associated stateful widget has been updated by outside forces.

In Flutter, (nearly) everything is a widget, and widgets are just Dart classes that know how to describe their view. They’re blueprints that Flutter will use to paint elements on the screen. The widget class is the the only view model that Flutter knows about. There aren’t separate controllers or views.

Widgets are components like React Native

When a Flutter builds a StatefulWidget, it creates a State object. This object is where all the mutable state for that widget is held.

The concept of state is defined by two things:

       The data used by the widget might change.

       The data can't be read synchronously when the widget is built. (All state must be established by the time the build method is called)

There are two types of widgets in Flutter based on state. 

All the view you see on app, they are called widgets in Flutter. So they are 

      Stateless

     Stateful

 

Stateless Widget

This type of widgets can not be redrawn if the state changes. Stateless widgets can be drawn only once during it’s life time. That’s it’s called stateless. 

Variables in flutter can be changed. If they are changed, in general build method is called. For stateless widgets, even though the variables change, the build method is not get called, thus no update the view.

Stateless widgets are dumb, it's ok to destroy them since, they just help you display information. No interaction with users. 

Stateless widgets dont' need to manage state variables. 

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home:Scaffold(
      appBar: AppBar(
        title:Text("hi"),
        
      ),
      body:Center(
        child:Text("I love Flutter"),
      )
  )));
}

 

Stateful Widget

On the other hand, if the variable of a stageful widget is changed, the build method is called and an updated view is shown on the screen. 

    import 'package:flutter/material.dart';

    class ScreenLifecyle extends StatefulWidget {
    ScreenLifecyleState state;

    //createState(): When the Framework is instructed to build a StatefulWidget, it immediately calls createState()
    @override
    State<StatefulWidget> createState() {
        // TODO: implement createState
        return ScreenLifecyleState();
    }
    }

    class ScreenLifecyleState extends State<ScreenLifecyle> {
    /*
    mounted is true: When createState creates your state class, a buildContext is assigned to that state.
    BuildContext is, overly simplified, the place in the widget tree in which this widget is placed.
    Here's a longer explanation. All widgets have a bool this.mounted property.
    It is turned true when the buildContext is assigned. It is an error to call setState when a widget is unmounted.
    mounted is false: The state object can never remount, and an error is thrown is setState is called.
    */

    /*
    This is the first method called when the widget is created (after the class constructor, of course.)
    initState is called once and only once. It must called super.initState().
    */
    @override
    void initState() {
        // TODO: implement initState
        super.initState();
        print("initState");
    }

    /*
    This method is called immediately after initState on the first time the widget is built.
    */
    @override
    void didChangeDependencies() {
        // TODO: implement didChangeDependencies
        super.didChangeDependencies();
        print("didChangeDependencies");
    }

    /*
    build(): This method is called often. It is required, and it must return a Widget.
    */
    @override
    Widget build(BuildContext context) {
        print("build");

        // TODO: implement build
        return Container();
    }

    /*
    If the parent widget changes and has to rebuild this widget (because it needs to give it different data),
    but it's being rebuilt with the same runtimeType, then this method is called.
    This is because Flutter is re-using the state, which is long lived.
    In this case, you may want to initialize some data again, as you would in initState.
    */
    @override
    void didUpdateWidget(ScreenLifecyle oldWidget) {
        print("didUpdateWidget");

        // TODO: implement didUpdateWidget
        super.didUpdateWidget(oldWidget);
    }

    @override
    void setState(fn) {
        print("setState");

        // TODO: implement setState
        super.setState(fn);
    }

    /*
    Deactivate is called when State is removed from the tree,
    but it might be reinserted before the current frame change is finished.
    This method exists basically because State objects can be moved from one point in a tree to another.
    */
    @override
    void deactivate() {
        // TODO: implement deactivate
        print("deactivate");
        super.deactivate();
    }

    /*
    Dispose is called when the State object is removed, which is permanent.
    This method is where you should unsubscribe and cancel all animations, streams, etc.
    */
    @override
    void dispose() {
        // TODO: implement dispose
        super.dispose();
     }

       @override
        void didChangeAppLifecycleState(AppLifecycleState state) {
            super.didChangeAppLifecycleState(state);
            switch (state) {
            case AppLifecycleState.inactive:
                print('appLifeCycleState inactive');
                break;
            case AppLifecycleState.resumed:
                print('appLifeCycleState resumed');
                break;
            case AppLifecycleState.paused:
                print('appLifeCycleState paused');
                break;
            case AppLifecycleState.suspending:
                print('appLifeCycleState suspending');
                break;
            }
        }

  }

Stateful widgets are mutable, which means this widget interact with users and send new update to the screen. 

Let's go through the above code step by step

createState()

Flutter says, hey let's build a stateful application then createState() is called. Then an object is created. 

Flutter framework can call this method multiple times over the lifetime of a stateful widget. For example, if the widget is inserted at multiple locations at the tree, the framework will create a separate state object using this method. 

This method is also called when a widget is inserted into the tree, it's called again when a widget is removed from the tree.

initState()

What do you want to do with this object?

Yes, let's put in the render tree and initialize some stuffs.  This is the first lifecycle method that is called when a widget is created. this is also get called before the build method.

DidUpdateDependencies()

This is right after initState. This is also get called when the dependencies change. This method could be called multiple times as the dependencies change.

DidUpdateWidget()

This is called whenever the configuration of a widget change. Things like passing variables down to constructor ,

like if you want to change the animation duration when the app runs. 

You also need to remember that super.DidUpdateWidget() should be the first line inside this code.

Deactivate()

This is called when an object is removed from the tree. This could be called moving a widget in the widget tree using a globalKey.

super.deactivate() method must be called at the bottom of this function. 

Dispose()

This is called when an object is removed from the tree permanently. For example when you want to move between widgets. If you want to move from current widget to Navigator.pushReplacement, then dispose() method would get called.

super.dispose() should be at the bottom of this method.

Build()

This method is called right after initState() and every time when you change the state variable. This method also gets called

  • After calling initState
  • After calling didUpdateWidget
  • After receiving a call to setState
  • After dependencies of this state object changes
  • After calling deactivating
  • After reinserting widget in the tree

This method can potentially be called in every frame and should not have any side effects beyond building a widget.

class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context){
  return MaterialApp(
    home:MyStatefulWidget(),
  );
  }
}

setState()

setState() is another important function in Flutter. We should use this when we want to make an internal change of object.  Call setState() means something has changed in this state, in this object. 

setState(() { _myState = newValue; });

newValue is the new value which is set for _mySate. And _myState would be varibale declared in a stateful widget class.