Flutter:在简历上更新小部件?

Posted

技术标签:

【中文标题】Flutter:在简历上更新小部件?【英文标题】:Flutter: Update Widgets On Resume? 【发布时间】:2018-09-26 22:26:00 【问题描述】:

在 Flutter 中,有没有一种方法可以在用户离开应用程序并立即返回时更新小部件?我的应用是基于时间的,尽快更新时间会很有帮助。

【问题讨论】:

【参考方案1】:

您可以通过这样做来监听生命周期事件,例如:

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';

class LifecycleEventHandler extends WidgetsBindingObserver 
  final AsyncCallback resumeCallBack;
  final AsyncCallback suspendingCallBack;

  LifecycleEventHandler(
    this.resumeCallBack,
    this.suspendingCallBack,
  );

  @override
  Future<void> didChangeAppLifecycleState(AppLifecycleState state) async 
    switch (state) 
      case AppLifecycleState.resumed:
        if (resumeCallBack != null) 
          await resumeCallBack();
        
        break;
      case AppLifecycleState.inactive:
      case AppLifecycleState.paused:
      case AppLifecycleState.detached:
        if (suspendingCallBack != null) 
          await suspendingCallBack();
        
        break;
    
  




class AppWidgetState extends State<AppWidget> 
  void initState() 
    super.initState();

    WidgetsBinding.instance.addObserver(
      LifecycleEventHandler(resumeCallBack: () async => setState(() 
        // do something
      ))
    );
  
  ...

【讨论】:

我只是想知道,您可以将 WidgetsBindingObserver 添加到 StatelessWidget 吗?谢谢。 当然可以,但是当这样的生命周期事件发生时你想做什么? 你可以把上面的代码放在任何地方。它不必在小部件内。这只是一个例子。 FutureVoidCallback 在哪里定义?我在颤振包源中找不到它,谷歌也没有帮助? @ChrisCrowe 你是对的。你需要自己声明。 typedef FutureVoidCallback = Future&lt;void&gt; Function();【参考方案2】:

使用系统频道:

import 'package:flutter/services.dart';

SystemChannels.lifecycle.setMessageHandler((msg)
  debugPrint('SystemChannels> $msg');
  if(msg==AppLifecycleState.resumed.toString())setState(());
);

`

【讨论】:

这对其他人来说可能很明显,但我花了一段时间才弄清楚我需要在 Flutter runApp 调用之后将其移动到某个位置。 我们是否将这段代码放入 initState() 中? systemChannels 会像监听器一样监听生命周期的变化? msg 变量的类型是什么?为什么不是 AppLifecycleState 类型? @edhubbell 来自docs If you need the binding to be constructed before calling runApp, you can ensure a Widget binding has been constructed by calling the WidgetsFlutterBinding.ensureInitialized() function.【参考方案3】:

简单的方法:

import 'package:flutter/services.dart';

handleAppLifecycleState() 
    AppLifecycleState _lastLifecyleState;
    SystemChannels.lifecycle.setMessageHandler((msg) 

     print('SystemChannels> $msg');

        switch (msg) 
          case "AppLifecycleState.paused":
            _lastLifecyleState = AppLifecycleState.paused;
            break;
          case "AppLifecycleState.inactive":
            _lastLifecyleState = AppLifecycleState.inactive;
            break;
          case "AppLifecycleState.resumed":
            _lastLifecyleState = AppLifecycleState.resumed;
            break;
          case "AppLifecycleState.suspending":
            _lastLifecyleState = AppLifecycleState.suspending;
            break;
          default:
        
    );
  

只需在您的init() 中添加handleAppLifecycleState()

class AppLifecycleReactor extends StatefulWidget 
      const AppLifecycleReactor( Key key ) : super(key: key);

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

    class _AppLifecycleReactorState extends State<AppLifecycleReactor> with WidgetsBindingObserver 
      @override
      void initState() 
        super.initState();
        WidgetsBinding.instance.addObserver(this);
      

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

      AppLifecycleState _notification;

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

      @override
      Widget build(BuildContext context) 
        return Text('Last notification: $_notification');
      
    

更多详情请参考documentation

【讨论】:

【参考方案4】:

对于深度测试,我认为结果值得一读。如果您对应该使用哪种方法感到好奇,请阅读以下内容:(在 android 上测试)

LifeCycle 解决方案共有三种方法。

    WidgetsBindingObserver SystemChannels.lifecycle flutter-android-lifecycle-plugin

WidgetsBindingObserverSystemChannels.lifecycle 的主要区别在于WidgetsBindingObserver 有更多的能力如果你有一堆小部件需要监听 LifeCycle。 SystemChannels 是更底层的,由WidgetsBindingObserver 使用。

经过多次测试,如果你在runApp之后使用SystemChannels,并且home widget mixin与WidgetsBindingObserver,home widget会失败,因为SystemChannels.lifecycle.setMessageHandler覆盖了home的方法。

因此,如果您想使用全局、单一的方法,请选择SystemChannels.lifecycle,其他人选择WidgetsBindingObserver

那么第三种方法呢?这仅适用于 Android,如果您必须在 之前 runApp 绑定您的方法,这是唯一的方法。

【讨论】:

如果使用SystemChannels.lifecycle,则不会收到WidgetsBindingObserver 回调。 加一详细说明【参考方案5】:
import 'package:flutter/material.dart';

abstract class LifecycleWatcherState<T extends StatefulWidget> extends State<T>
    with WidgetsBindingObserver 
  @override
  Widget build(BuildContext context) 
    return null;
  

  @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:
        onResumed();
        break;
      case AppLifecycleState.inactive:
        onPaused();
        break;
      case AppLifecycleState.paused:
        onInactive();
        break;
      case AppLifecycleState.detached:
        onDetached();
        break;
    
  

  void onResumed();
  void onPaused();
  void onInactive();
  void onDetached();

示例

class ExampleStatefulWidget extends StatefulWidget 
  @override
  _ExampleStatefulWidgetState createState() => _ExampleStatefulWidgetState();


class _ExampleStatefulWidgetState
    extends LifecycleWatcherState<ExampleStatefulWidget> 
  @override
  Widget build(BuildContext context) 
    return Container();
  

  @override
  void onDetached() 

  

  @override
  void onInactive() 

  

  @override
  void onPaused() 

  

  @override
  void onResumed() 

  

【讨论】:

【参考方案6】:

下面是一个如何观察包含活动 (Flutter for Android developers) 的生命周期状态的示例:

import 'package:flutter/widgets.dart';

class LifecycleWatcher extends StatefulWidget 
  @override
  _LifecycleWatcherState createState() => _LifecycleWatcherState();


class _LifecycleWatcherState extends State<LifecycleWatcher> with WidgetsBindingObserver 
  AppLifecycleState _lastLifecycleState;

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

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

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) 
    setState(() 
      _lastLifecycleState = state;
    );
  

  @override
  Widget build(BuildContext context) 
    if (_lastLifecycleState == null)
      return Text('This widget has not observed any lifecycle changes.', textDirection: TextDirection.ltr);

    return Text('The most recent lifecycle state this widget observed was: $_lastLifecycleState.',
        textDirection: TextDirection.ltr);
  


void main() 
  runApp(Center(child: LifecycleWatcher()));

【讨论】:

【参考方案7】:

使用“WidgetsBindingObserver”检测 onResume 事件的解决方案 或“SystemChannels.lifecycle”仅在应用程序完全进入后台时才有效,例如在锁定屏幕事件期间或切换到另一个应用程序期间。如果用户在应用程序的屏幕之间导航,它将不起作用。如果即使在同一应用的不同屏幕之间切换时也想检测 onResume 事件,请从此处使用 visibility_detector 库:https://pub.dev/packages/visibility_detector

  @override
Widget build(BuildContext context) 
  return VisibilityDetector(
    key: Key('my-widget-key'),
    onVisibilityChanged: (visibilityInfo) 
      num visiblePercentage = visibilityInfo.visibleFraction * 100;
      debugPrint(
          'Widget $visibilityInfo.key is $visiblePercentage% visible');
      if(visiblePercentage == 100)
                debugPrint("Resumed !");
              
    ,
    child: someOtherWidget,
  );

【讨论】:

【参考方案8】:

如果你想执行 onResume 方法但只在一个页面中,你可以在你的页面中添加这个:

var lifecycleEventHandler;

@override
  void initState() 
    super.initState();

    ///To listen onResume method
    lifecycleEventHandler = LifecycleEventHandler(
        resumeCallBack: () async 
          //do something
        
    );
    WidgetsBinding.instance.addObserver(lifecycleEventHandler);
  

@override
  void dispose() 
    if(lifecycleEventHandler != null)
      WidgetsBinding.instance.removeObserver(lifecycleEventHandler);

    super.dispose();
  

并将 LifecycleEventHandler 类作为这篇文章的第一个答案:

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';

class LifecycleEventHandler extends WidgetsBindingObserver 
  final AsyncCallback resumeCallBack;
  final AsyncCallback suspendingCallBack;

  LifecycleEventHandler(
    this.resumeCallBack,
    this.suspendingCallBack,
  );

  @override
  Future<void> didChangeAppLifecycleState(AppLifecycleState state) async 
    switch (state) 
      case AppLifecycleState.resumed:
        if (resumeCallBack != null) 
          await resumeCallBack();
        
        break;
      case AppLifecycleState.inactive:
      case AppLifecycleState.paused:
      case AppLifecycleState.detached:
        if (suspendingCallBack != null) 
          await suspendingCallBack();
        
        break;
    
  

【讨论】:

以上是关于Flutter:在简历上更新小部件?的主要内容,如果未能解决你的问题,请参考以下文章

如何从另一个小部件类更新小部件树 - Flutter

由于当前屏幕上的更新,防止 Flutter Provider 在前一屏幕中重建小部件

Flutter:从子 StreamBuilder 更新有状态小部件

Flutter 不更新子小部件

当 Flutter 中的全局变量更改(异步)时更新小部件

Flutter ListView 与 List 中的小部件不会在应该更新时更新