颤动中的生命周期

Life cycle in flutter

flutter 是否有像 Activity.resume() 这样的方法可以告诉开发人员用户已经返回到 activity。

当我在Page-B中从网络中获取数据并返回到Page-A时,如何让Page-A知道数据已准备好。

这里有一个例子:https://github.com/flutter/flutter/blob/master/examples/layers/services/lifecycle.dart

您需要使用WidgetsBindingObserver

  1. createState(): 当指示 Framework 构建 StatefulWidget 时,它会立即调用 createState()

  2. mounted 为真:createState 创建您的状态 class 时,一个 buildContext 被分配给该状态。 buildContext 是过于简化的小部件树中放置此小部件的位置。这是一个更长的解释。 所有小部件都有一个 bool this.mounted 属性。当分配 buildContext 时,它变为真。卸载小部件时调用 setState 是错误的。

  3. initState(): 这是创建小部件时调用的第一个方法(当然是在 class 构造函数之后。) initState 被调用一次且仅调用一次。它必须调用 super.initState().

  4. didChangeDependencies(): 在第一次构建小部件 initState 之后立即调用此方法。

  5. build(): 这个方法经常被调用。它是必需的,并且必须 return 一个 Widget。

  6. didUpdateWidget(Widget oldWidget): 如果父窗口部件发生变化并且必须重建这个窗口部件(因为它需要给它不同的数据),但是它正在用相同的 runtimeType 重建,那么这个方法就会被调用。 这是因为 Flutter 正在重新使用长期存在的状态。在这种情况下,您可能需要像在 initState.

    中一样再次初始化一些数据
  7. setState(): 通常从框架本身和开发人员调用此方法。它用于通知框架数据已更改

  8. deactivate(): 当 State 从树中移除时调用 Deactivate,但它可能会在当前帧更改完成之前重新插入。这种方法的存在主要是因为 State 对象可以从树中的一个点移动到另一个点。

  9. dispose(): dispose() State 对象被移除时调用,这是永久的。此方法是您应该取消订阅并取消所有动画、流等的地方。

  10. mounted 为假: 状态对象永远无法重新挂载,如果调用 setState 将抛出错误。

我认为 flutter 应用程序生命周期回调不会在这里帮助你。你可以试试这个逻辑。

在第 1 页(导航到第 2 页时)

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

在第 2 页(导航回第 1 页时)

Navigator.pop(context, returnedValue);

生命周期回调

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

应用生命周期

对于 LifeCycle,您需要使用 WidgetsBindingObserver 它会在应用程序进入前台和后台时运行。

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

但就我而言,当我从一个屏幕移动到另一个屏幕时,我无法捕捉到 OnResume 的情况。所以下面的代码与 startActivityForResult.

的工作方式类似

当您联系到另一个人时使用此代码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');
            });

当你按回键时

onPressed: (){Navigator.pop(context,length);}

构造函数

这个函数不是生命周期的一部分,因为此时widget的State属性是空的,如果想在构造函数中访问widget的属性是行不通的。但是构造函数必须要先调用。

创建状态

当 Flutter 被指示构建一个 StatefulWidget 时,它会立即调用 createState()

初始状态

当这个对象被插入到树中时调用。

调用时插入渲染树时,该函数在生命周期内只调用一次。这里可以做一些初始化,比如初始化State变量。

setState

setState() 方法经常被 Flutter 框架本身和开发人员调用。

didChangeDependencies

当此 [State] 对象的依赖项发生变化时调用。

didUpdateWidget

每当小部件配置更改时调用。

停用

当此对象从树中移除时调用。 在dispose之前,我们会调用这个函数。

处置

当此对象从树中永久删除时调用。

didChangeAppLifecycleState

当系统将应用置于后台或returns将应用置于前台时调用。

这里有一个很好的详细文档: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;
            }
        }

  }
 

只有 StatefulWidget 保持状态。 它的生命周期如下

  • createState() : 当我们新建一个StatefulWidget的时候,这个马上调用createState(),这个override方法必须存在
  • initState() :它是 Widget 之后调用的第一个方法 created.This 相当于我们的 onCreate() 和 viewDidLoad()
  • didChangeDependencies() :在第一次构建小部件时,在 initState() 之后立即调用此方法
  • build() :在 didChangeDependencies() 之后调用。所有 GUI 都在这里渲染,每次 UI 需要渲染时都会调用
  • didUpdateWidget() :一旦父 Widget 进行了更改并需要重绘 UI
  • ,就会调用它
  • deactivate() :每当从树中删除此 State 对象时,框架都会调用此方法
  • dispose() :当此对象及其状态从树中永久删除并且永远不会再次构建时调用。

AppLifecycleState如下

  • inactive - 应用程序处于非活动状态并且不 接收用户输入。仅iOS

  • paused - 该应用程序当前对用户不可见,不是 响应用户输入,并在后台 运行。

  • 已恢复 - 应用程序可见并响应用户输入。

  • suspending - 应用程序将暂时挂起。 Android 只有

  1. createState(): 当我们创建一个有状态的widget时,Flutter框架会调用createState()方法。

    @覆盖 _DeveloperLibsWidgetState createState() => _DeveloperLibsWidgetState();

2.mounted(true/false):一旦我们创建了一个 State 对象,框架在调用 initState() 之前通过将它与 BuildContext 相关联来挂载 State 对象方法。所有小部件都安装了一个 bool 属性。分配 buildContext 时变为真。

bool get mounted => _element != null;
  1. initState():这是在 class 构造函数之后创建有状态小部件时调用的第一个方法。 initState() 只被调用一次。它必须调用 super.initState()。

    @覆盖 初始化状态(){ super.initState(); // 去做 }

  2. didChangeDependencies():第一次构建小部件时,在 initState() 方法之后立即调用此方法。

    @受保护 @mustCallSuper void didChangeDependencies() {

    }

  3. build():它显示了由小部件表示的用户界面部分。框架在几种不同的情况下调用此方法: 在调用 initState() 方法之后。 框架总是在调用 didUpdateWidget 之后调用 build() 方法 在收到 setState 更新屏幕的调用后。

    @覆盖 小部件构建(BuildContext 上下文,MyButtonState 状态){ return容器(颜色:常量颜色(0xFF2DBD3A));
    }

  4. didUpdateWidget(Widget oldWidget):如果父widget改变了配置并且必须重建这个widget。但是它正在使用相同的 runtimeType 重建,然后调用 didUpdateWidget() 方法。

    @mustCallSuper @protected void didUpdateWidget(协变 T oldWidget){

    }

  5. setState():该方法由框架和开发者调用。我们可以更改 State 对象的内部状态,并在传递给 setState() 的函数中进行更改。

    @覆盖 _DeveloperLibsWidgetState createState() => _DeveloperLibsWidgetState();

  6. deactivate():当 State 从 widgets 树中移除时调用,但它可能会在当前帧更改完成之前重新插入。

    @受保护 @mustCallSuper void deactivate() { }

  7. dispose():当State对象被永久移除时调用。在这里您可以取消订阅和取消所有动画、流等

    @受保护 @mustCallSuper 无效处置(){ 断言(_debugLifecycleState == _StateLifecycle.ready); assert(() { _debugLifecycleState = _StateLifecycle.defunct; return true; }()); }

因为这里的每个人都在谈论应用程序生命周期,而不是解决 OP 提出的问题。这是问题的答案。

要求是他想从 A 页面打开 B 页面,比方说从 B 页面选择文件,一旦文件 selected 他想回到 A 页面并需要处理那个 select在页面A中编辑文件。就像在android中一样,我们可以在onActivityResult()方法中完成。下面是我们在flutter中可以实现的方式。

您可以从A页打开B页,如下所示

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.**

    }

在页面 B 中,您可以 select 文件或您需要的任何东西 return 到页面 A,如下所示(return 文件或任何其他变量在 selection.

之后
Navigator.of(context).pop({'selection':file});

您可以在 Flutter 扩展 LifecycleState class 中模拟 onResumeonPause 状态。确保使用 push() 或 pushNamed() 方法推送新路由。

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

我知道我可能来晚了一点,但我会回答这个问题,以防其他人需要答案, 请参考这个解决方案 但我想澄清一些事情,在实现 RouteAware mixin 后的有状态小部件中,请注意:

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