生命周期在颤动

时间:2017-01-05 07:17:34

标签: flutter

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

当我从Page-B中的互联网中选择数据并返回到Page-A时,我怎样才能让Page-A知道数据已准备好。

10 个答案:

答案 0 :(得分:18)

  1. createState(): 当指示框架构建StatefulWidget时,它将立即调用createState()

  2. 已安装为真: 当createState创建状态类时,会将buildContext分配给该状态。 BuildContext被过度简化,该小部件在小部件树中的放置位置。这是更长的解释。 所有小部件都具有bool this.mount属性。分配buildContext后,它变为true。卸载小部件时调用setState是错误的。

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

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

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

  6. didUpdateWidget(Widget oldWidget): 如果父窗口小部件发生更改并且必须重建此窗口小部件(因为需要为其提供不同的数据),但是使用相同的runtimeType对其进行重建,则将调用此方法。 这是因为Flutter正在重用长期存在的状态。在这种情况下,您可能希望像initState一样再次初始化一些数据。

  7. setState(): 通常从框架本身和开发人员调用此方法。它用于通知框架数据已更改

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

  9. dispose(): 当移除State对象时,将调用Dispose,这是永久的。 您可以在此方法退订并取消所有动画,流等。

  10. 安装错误: 状态对象永远无法重新安装,并且调用setState会引发错误。

答案 1 :(得分:15)

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

您需要使用WidgetsBindingObserver

答案 2 :(得分:3)

enter image description here 构造函数

此功能不是生命周期的一部分,因为这次小部件属性的状态为空,如果要访问构造函数中的小部件属性将无法正常工作。但是构造函数必须是第一个调用。

createState

在指示Flutter建立StatefulWidget时,它会立即调用createState()

初始化状态

在将该对象插入树中时调用。

在调用时插入渲染树时,此函数在生命周期中仅被调用一次。在这里,您可以进行一些初始化,例如初始化状态变量。

setState

通常从Flutter框架本身和开发人员中调用setState()方法。

didChangeDependencies

此[State]对象的依赖项更改时调用。

didUpdateWidget

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

停用

从树中删除此对象时调用。 在处理之前,我们将调用此函数。

处置

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

didChangeAppLifecycleState

在系统将应用程序置于后台或将应用程序返回至前台时调用。

以下是详细的文档:https://flutterbyexample.com/stateful-widget-lifecycle/

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

  }

答案 3 :(得分:3)

  1. createState():当我们创建有状态窗口小部件时,Flutter框架会指示createState()方法。

    @override _DeveloperLibsWidgetState createState()=> _DeveloperLibsWidgetState();

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

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

    @override initState(){ super.initState(); // 去做 }

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

    @受保护 @mustCallSuper void didChangeDependencies(){

    }

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

    @override 窗口小部件构建(BuildContext上下文,MyButtonState状态){ return Container(color:const Color(0xFF2DBD3A));
    }

  4. didUpdateWidget(Widget oldWidget):如果父窗口小部件更改了配置并且必须重新构建此窗口小部件。但是正在使用相同的runtimeType对其进行重建,然后调用didUpdateWidget()方法。

    @mustCallSuper @受保护 void didUpdateWidget(协变量T oldWidget){

    }

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

    @override _DeveloperLibsWidgetState createState()=> _DeveloperLibsWidgetState();

  6. deactivate():当从窗口小部件树中删除状态时调用此方法,但可能会在当前帧更改完成之前重新插入状态。

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

  7. dispose():在永久删除State对象时调用。在这里您可以取消订阅并取消所有动画,视频流等。

    @受保护 @mustCallSuper 无效dispose(){ assert(_debugLifecycleState == _StateLifecycle.ready); assert((){_debugLifecycleState = _StateLifecycle.defunct;返回true;}()); }

答案 4 :(得分:2)

应用生命周期

对于LifeCycle,您需要使用WidgetsBindingObserver该应用程序在前台和后台运行时都可以正常工作。

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

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


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


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

但是对于我来说,当我从一个屏幕转到另一个屏幕时,我无法捕捉到OnResume的情况。因此下面的代码与startActivityForResult类似。

进行其他活动时使用此代码

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

当您按下后退

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

答案 5 :(得分:2)

StatefulWidget 保持状态。 其生命周期如下

  • createState():当我们构建一个新的StatefulWidget时,此函数立即调用createState(),并且此覆盖方法必须存在
  • initState():这是在创建窗口小部件之后调用的第一个方法,这等效于onCreate()和viewDidLoad()
  • didChangeDependencies():第一次构建窗口小部件后,在initState()之后立即调用此方法
  • build():在didChangeDependencies()之后立即调用。所有的GUI都在此处呈现,并且每次需要呈现UI时都会被调用
  • didUpdateWidget():父窗口小部件进行更改并需要重新绘制用户界面后,它将被调用
  • deactivate():只要框架从树中删除此State对象,框架就会调用此方法
  • dispose():当该对象及其状态从树中永久移除并且永远不会再次构建时,将调用它。

AppLifecycleState如下

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

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

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

  • 挂起-该应用程序将暂时挂起。 Android 仅

答案 6 :(得分:1)

我认为不稳定的应用程序生命周期回调不会在这里为您提供帮助。您可以尝试这种逻辑。

在第一页(导航到第二页时)

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

在第二页中(导航回第一页时)

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

答案 7 :(得分:0)

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

要求是他要从A页打开B页,假设要从B页中选择文件,并且一旦选择了文件,他想返回A页并需要处理A页中的所选文件。 android,我们可以在onActivityResult()方法中做到这一点。以下是我们在颤振中可以实现的方法。

您可以从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中,您可以选择文件或需要返回到页面A的内容,如下所示(选择后返回文件或其他任何变量。

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

答案 8 :(得分:0)

您可以在您的 Flutter 扩展 onResume 类中模拟 onPauseLifecycleState 状态。确保使用 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;
}

答案 9 :(得分:0)

我知道我可能会迟到但会回答这个问题以防其他人需要答案, 请参考此解决方案https://stackoverflow.com/a/58504433/3037840 但我想澄清一些事情,在实现 RouteAware 混合后的有状态小部件中,请注意:

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