Life cycle in flutter
Asked Answered
S

11

154

Does flutter have a method like Activity.resume() which can tell developer the user has gone back to the activity.

When I pick the data from internet in Page-B and go back to Page-A, how can I let Page-A know that the data is prepared.

Shocker answered 5/1, 2017 at 7:17 Comment(5)
I don't fully understand the question: Do you simply want to pass data to the screen before the current screen on the navigation stack?Xenocrates
Check this link medium.com/flutter-community/…Staccato
I wrote an answer that talks about all the equivalent lifecycle methods of Flutter vs iOS vs Android here: https://mcmap.net/q/159718/-flutter-exact-lifecycle-equivalents-to-onresume-onpause-on-android-and-viewwillappear-viewdiddisappear-on-iosParticulate
For those not familiar with Java/Kotlin, would you mind to explain what an Activity is? That's a beautiful answer to that question, @KyleVennBrawl
The simplified answer: Activity = Widget that acts as a route/page. Activity = UIViewController = Widget. But widgets are more technically similar to a combo of fragments and views in the Android ecosystem.Particulate
G
309
# METHOD DESCRIPTION
1 createState() When the Framework is instructed to build a StatefulWidget, it immediately calls createState()
2 mounted is true When createState creates your state class, a buildContext is assigned to that state. buildContext is the place in the widget tree in which this widget is placed. 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.
3 initState() 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 call super.initState().
4 didChangeDependencies() This method is called immediately after initState on the first time the widget is built.
5 build() This method is called often. It is required, and it must return a Widget.
6 didUpdateWidget(Widget oldWidget) 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.
7 setState() This method is called often from the framework itself and from the developer. It's used to notify the framework that data has changed.
8 deactivate() deactivate() is called when the State object is removed from the tree, but it might be reinserted before the current frame change is finished. This method exists because State objects can be moved from one point in a tree to another.
9 dispose() 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.
10 mounted is false The state object can never remount, and an error will be thrown if setState is called.
Glim answered 19/11, 2018 at 17:25 Comment(8)
You should clarify what classes these methods exist on. createState and initState are on two different classes.Starvation
Hi @Shelly, If app get crashed due to low memory issue, which method of the page will be called?Lampley
What is the correct place to use FutureBuilder? Is it initState or didChangeDependencies?Naima
@Rap please update the link or remove from here. Thanks.Dyann
isn't there a method for when the widget is not visible but still exists? For example when adding a screen to the stack?Lotti
I don't think that all widgets have a bool this.mounted property, cuz this only exists in the State class.Aerosol
https://mcmap.net/q/159719/-how-to-check-when-my-widget-screen-comes-to-visibility-in-flutter-like-onresume-in-android u can check thisOsei
From the docs: "The framework always calls build after calling didUpdateWidget, which means any calls to setState in didUpdateWidget are redundant"Rehearing
C
71

enter image description here Constructor

This function is not part of the life cycle, because this time the State of the widget property is empty, if you want to access the widget properties in the constructor will not work. But the constructor must be to the first call.

createState

When Flutter is instructed to build a StatefulWidget, it immediately calls createState()

Init State

Called when this object is inserted into the tree.

When inserting the render tree when invoked, this function is called only once in the life cycle. Here you can do some initialization, such as initialization State variables.

setState

The setState() method is called often from the Flutter framework itself and from the developer.

didChangeDependencies

Called when a dependency of this [State] object changes.

didUpdateWidget

Called whenever the widget configuration changes.

deactivate

Called when this object is removed from the tree. Before dispose, we will call this function.

dispose

Called when this object is removed from the tree permanently.

didChangeAppLifecycleState

Called when the system puts the app in the background or returns the app to the foreground.

Here is a good detail document: https://www.bookstack.cn/read/flutterbyexample/aebe8dda4df3319f.md

    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;
            }
        }

  }
 
Catheterize answered 29/8, 2019 at 5:3 Comment(1)
Can you explain why the build() method from Stateful points back to the constructor in Stateless?Brawl
C
25

There's an example here: https://github.com/flutter/flutter/blob/master/examples/layers/services/lifecycle.dart

You need to use WidgetsBindingObserver

Collinsia answered 5/1, 2017 at 8:3 Comment(0)
S
22

Only StatefulWidget hold state . Lifecyle of it is as follow

  • createState () : When we build a new StatefulWidget, this one calls createState() right away and this override method must exist
  • initState() :it is the first method called after the Widget is created.This is our equivalent to onCreate() and viewDidLoad()
  • didChangeDependencies() : This method is called immediately after initState() on the first time the widget is built
  • build() : called right after didChangeDependencies(). All the GUI is render here and will be called every single time the UI needs to be render
  • didUpdateWidget() : it’ll be called once the parent Widget did a change and needs to redraw the UI
  • deactivate() : framework calls this method whenever it removes this State object from the tree
  • dispose() :is called when this object and its State is removed from the tree permanently and will never build again.

AppLifecycleState are as follows

  • inactive - The application is in an inactive state and is not receiving user input. iOS only

  • paused - The application is not currently visible to the user, not responding to user input, and running in the background.

  • resumed - The application is visible and responding to user input.

  • suspending - The application will be suspended momentarily. Android only

Shulins answered 10/12, 2019 at 7:1 Comment(5)
how can I detect on Page1 that I moved back from Page2?Contrabass
I tried deactivate but it get calls also when it loadsContrabass
Tried dispose ?Shulins
@Contrabass are you using Stateful wideget ?Shulins
No, just Stateless but it needs to be like thatContrabass
T
21

App Lifecycle

For LifeCycle, you need to use WidgetsBindingObserver it works when the app goes on foreground and background.

import 'package:flutter/widgets.dart';
  class YourWidgetState extends State<YourWidget> with WidgetsBindingObserver {

       @override
      void initState() {
        super.initState();
        WidgetsBinding.instance.addObserver(this);
      }


      @override
      void dispose() {
        WidgetsBinding.instance.removeObserver(this);
        super.dispose();
      }


       @override
      void didChangeAppLifecycleState(AppLifecycleState state) {
        if (state == AppLifecycleState.resumed) {
           //do your stuff
        }
      }
    }

But in my case, i was unable to catch the situation of OnResume when I move from one screen to another. so below code working similarly as startActivityForResult.

use this code when your reaching to another activity

Navigator.push(context,
              MaterialPageRoute(builder: (context) => ProductDetails(pid: productList[index]["pid"],),
                  settings: RouteSettings(name: '/productdetail')),).then((value){
                    setState(() {
                      length=value;
                    });
                    debugPrint('CHECK BACK FROM DETAIL $length');
            });

when you press back

onPressed: (){Navigator.pop(context,length);}
Troublous answered 19/3, 2019 at 5:57 Comment(0)
C
8

I don't think flutter app lifecycle callbacks are going to help you here. You can try this logic.

In 1st page (when navigating to 2nd page)

Navigator.push(context, MaterialPageRoute(builder: (context) => Page2())).then((value) {
  print("Value returned form Page 2 = $value");
};

In 2nd page (when navigating back to 1st page)

Navigator.pop(context, returnedValue);

Lifecycle callback

void main() => runApp(HomePage());

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    print("Current state = $state");
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Lifecycle")),
        body: Center(child: Text("Center"),),
      ),
    );
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
}
Comply answered 5/2, 2019 at 15:9 Comment(2)
@OliverDixon I answered what OP asked. Not sure what you were looking for.Comply
where to put this Navigator.pop(context, returnedValue); ?? in the second pageFusible
M
1

I know I might be a little bit late but will answer this question in case someone else needs an answer, please refer to this solution https://mcmap.net/q/159719/-how-to-check-when-my-widget-screen-comes-to-visibility-in-flutter-like-onresume-in-android but I want to clarify something, in your stateful widget after implementing the RouteAware mixin, please note that:

@override
  void didPushNext() { //similar to onPause
    // will be called when a new route has been pushed, and the current route is no longer visible. acts similar to onPause
  }

  @override
  void didPopNext() { //similar to onResume
     // will be called when the top route has been popped off, and the current route shows up. acts similar to onResume when you are navigated back to your activity/fragment
  }
Meristic answered 3/6, 2021 at 4:52 Comment(0)
C
0

Since everyone here is talking about app life cycle and not addressing the question which OP is asking. here is the answer to the question.

The requirement is he want to open page B from page A, let say to choose file from page B, and once file selected he want to go back to page A and need to process that selected file in page A. Like in android we can do it in onActivityResult() method. Below is the way we can achieve in flutter.

You can open the page B from page A as below

Map results =  await Navigator.of(context).push(MaterialPageRoute(
      builder: (BuildContext context) {
        return new PageB(title: "Choose File");
        },
      ));

    if (results != null && results.containsKey('selection')) {
      setState(() {
        _selection = results['selection'];
      });

    **//here you can do whatever you want to do with selection variable.**

    }

In Page B you can select the file or what ever things you need to return to page A as below (return file or any other variable after selection.

Navigator.of(context).pop({'selection':file});
Convertible answered 30/9, 2020 at 9:50 Comment(0)
F
0

You can simulate onResume and onPause states in your Flutter extending LifecycleState class. Make sure to push new routes using push() or pushNamed() method.

/// Inherit this State to be notified of lifecycle events, including popping and pushing routes.
///
/// Use `pushNamed()` or `push()` method to track lifecycle events when navigating to another route.
abstract class LifecycleState <T extends StatefulWidget> extends State<T>
    with WidgetsBindingObserver {
  ResumeResult resumeResult = new ResumeResult();
  bool _isPaused = false;

  AppLifecycleState lastAppState = AppLifecycleState.resumed;

  void onResume() {}

  void onPause() {}

  /// Use instead of Navigator.push(), it fires onResume() after route popped
Future<T> push<T extends Object>(BuildContext context, Route<T> route, [String source]) {
    _isPaused = true;
    onPause();

    return Navigator.of(context).push(route).then((value) {
        _isPaused = false;

        resumeResult.data = value;
        resumeResult.source = source;

        onResume();
        return value;
    });
}

/// Use instead of Navigator.pushNamed(), it fires onResume() after route popped
Future<T> pushNamed<T extends Object>(BuildContext context, String routeName, {Object arguments}) {
    _isPaused = true;
    onPause();

    return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments).then((value) {
        _isPaused = false;

        resumeResult.data = value;
        resumeResult.source = routeName;

        onResume();
        return value;
    });
}

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.paused) {
      if (!_isPaused) {
        onPause();
      }
    } else if (state == AppLifecycleState.resumed &&
        lastAppState == AppLifecycleState.paused) {
      if (!_isPaused) {
        onResume();
      }
    }
    lastAppState = state;
  }
}

class ResumeResult {
  dynamic data;
  String source;
}
Floriated answered 14/2, 2021 at 18:54 Comment(0)
D
0

You can use focus_detector package:

import 'package:focus_detector/focus_detector.dart';

...

class ScreenState extends State<Screen> {

  void onResume() {
    print("onResume");
  }

  void onPause() {
    print("onPause");
  }

  @override
  Widget build(BuildContext context) {
    return FocusDetector(
      onFocusGained: onResume,
      onFocusLost: onPause,
      child: Text('example'),
      );
  }
}
Discolor answered 14/2 at 8:6 Comment(0)
B
0

AppLifecycleListener Class (Flutter 3.13+)

  final lifecycleListener = AppLifecycleListener(
    onResume: () => debugPrint('App resumed'),
    onPause: () => debugPrint('App paused'),
    onInactive: () => debugPrint('App inactive'),
  );

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(lifecycleListener);
    super.dispose();
  }
Burgener answered 7/4 at 19:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.