onResume() 和 onPause() 用于 Flutter 上的小部件

onResume() and onPause() for widgets on Flutter

现在,一个小部件只有在第一次创建小部件时触发的 initeState() 和在小部件被销毁时触发的 dispose() 。有没有一种方法可以检测小部件何时返回前台?当一个小部件即将进入后台时,因为另一个小部件刚刚被置于前台? 它相当于 Android 触发的 onResume 和 onPause,以及 ios

触发的 viewWillAppear 和 viewWillDisappear

您想要执行此操作的最常见情况是您有动画 运行 并且您不想在后台消耗资源。在这种情况下,您应该使用 TickerProviderStateMixin 扩展 State,并使用 State 作为 AnimationControllervsync 参数。当您的 State 可见时,Flutter 将只负责调用动画控制器的侦听器。

如果您希望 PageRoute 中的 StatePageRoute 被其他内容遮挡时被处理掉,您可以传递一个 maintainState argument of false to your PageRoute constructor. If you do this, your State will reset itself (and its children) when it's hidden and will have to re-construct itself in initState using the properties passed in as constructor arguments to its widget. You can use a model or controller class, or PageStorage,如果您不想完全重置,则保留用户的进度信息。

这是一个演示这些概念的示例应用程序。

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    onGenerateRoute: (RouteSettings settings) {
      if (settings.name == '/') {
        return new MaterialPageRoute<Null>(
          settings: settings,
          builder: (_) => new MyApp(),
          maintainState: false,
        );
      }
      return null;
    }
  ));
}

class MyApp extends StatefulWidget {
  MyAppState createState() => new MyAppState();
}

class MyAppState extends State<MyApp> with TickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    print("initState was called");
    _controller = new AnimationController(vsync: this)
      ..repeat(min: 0.0, max: 1.0, period: const Duration(seconds: 1))
      ..addListener(() {
        print('animation value ${_controller.value}');
      });
    super.initState();
  }

  @override
  void dispose() {
    print("dispose was called");
    _controller.dispose();
    super.dispose();
  }

  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('home screen')
      ),
      body: new Center(
        child: new RaisedButton(
          onPressed: () {
            setState(() {
              _counter++;
            });
          },
          child: new Text('Button pressed $_counter times'),
        ),
      ),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.remove_red_eye),
        onPressed: () {
          Navigator.push(context, new MaterialPageRoute(
            builder: (BuildContext context) {
              return new MySecondPage(counter: _counter);
            },
          ));
        },
      ),
    );
  }
}

class MySecondPage extends StatelessWidget {
  MySecondPage({ this.counter });

  final int counter;

  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Certificate of achievement'),
      ),
      body: new Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          new Icon(Icons.developer_mode, size: 200.0),
          new Text(
            'Congrats, you clicked $counter times.',
            style: Theme.of(context).textTheme.title,
            textAlign: TextAlign.center,
          ),
          new Text(
            'All your progress has now been lost.',
            style: Theme.of(context).textTheme.subhead,
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }
}

有一个抽象的class调用者WidgetsBindingObserver

https://docs.flutter.io/flutter/widgets/WidgetsBindingObserver-class.html

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    setState(() {
            _notification = state;
    });
  }

有"state",可以管理为

switch(state) {
  case AppLifecycleState.resumed:
    // Handle this case
    break;
  case AppLifecycleState.inactive:
    // Handle this case
    break;
  case AppLifecycleState.paused:
    // Handle this case
    break;
  case AppLifecycleState.suspending:
    // Handle this case
    break;
}

这是一个演示如何正确处理事情的完整示例,要对此进行测试,请按主页按钮并恢复应用程序,您将看到正在调用 didChangeAppLifecycleState

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

class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();

    // Add the observer. 
    WidgetsBinding.instance!.addObserver(this);
  }

  @override
  void dispose() {
    // Remove the observer
    WidgetsBinding.instance!.removeObserver(this);

    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);

    // These are the callbacks
    switch (state) {
      case AppLifecycleState.resumed:
        // widget is resumed
        break;
      case AppLifecycleState.inactive:
        // widget is inactive
        break;
      case AppLifecycleState.paused:
        // widget is paused
        break;
      case AppLifecycleState.detached:
        // widget is detached
        break;
    }
  }

  @override
  Widget build(BuildContext context) => Scaffold();
}

我来晚了一点,但为那些将来可能正在寻找它的人提供了完美的解决方案。 Navigator.push() 实际上是一个 Future。这意味着它有 then() 回调函数。所以 then() 将在您从第二个屏幕调用 Navigator.pop() 之后被调用。甚至您可以从第二个屏幕发送一些数据并访问第一个屏幕中的数据。

示例:

//from Screen A
Navigator.of(context).push(MaterialPageRoute(builder:(context)=>B()))
.then((value)=>{ refresh() });

//in Screen B with data
Navigator.pop(context,[1]);

//or without data
Navigator.pop(context);

因此 refresh() 将在屏幕 A 的简历上调用。

我创建 visibility_aware_state 是因为它的行为类似于 Android 的 Activity.onResume()。它还考虑了弹出和推送导航。

class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends VisibilityAwareState<Example> {
  @override
  Widget build(BuildContext context) {
    // return your widget
  }

  @override
  void onVisibilityChanged(WidgetVisibility visibility) {
    switch(visibility) {
      case WidgetVisibility.VISIBLE:
        // Like Android's Activity.onResume()
        break;
      case WidgetVisibility.INVISIBLE:
        // Like Android's Activity.onPause()
        break;
      case WidgetVisibility.GONE:
        // Like Android's Activity.onDestroy()
        break;
    }
    super.onVisibilityChanged(visibility);
  }
}

Mamnarock您的回答正确但不完整,您分享的link不可用。

完整代码如下:

import 'package:flutter/material.dart';

class YourClass extends StatefulWidget {

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

class _YourClassState extends State<YourClass>
    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) {
    switch (state) {
      case AppLifecycleState.resumed:
        // Handle this case
        break;
      case AppLifecycleState.inactive:
        // Handle this case
        break;
      case AppLifecycleState.paused:
        // Handle this case
        break;
      case AppLifecycleState.detached:
        // Handle this case
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

正如评论中提到的 TeeTracker:

这是一个应用程序级别的生命周期,这意味着当整体恢复、不活动或暂停时,而不是单个小部件。