【问题标题】:How to execute code before app exit flutter如何在应用程序退出颤动之前执行代码
【发布时间】:2020-02-12 08:58:11
【问题描述】:

我想检测用户何时退出我的应用程序并执行一些代码,但我不知道该怎么做。我尝试使用这个包:https://pub.dev/packages/flutter_lifecycle_state 但我有这个错误:

flutter/.pub-cache/hosted/pub.dartlang.org/flutter_lifecycle_state-1.0.0/lib/flutter_lifecycle_state.dart:80:30:错误:找不到获取器:“暂停”。 案例 AppLifecycleState.suspending

如果您对此问题有任何解决方案或知道另一种方法来检测用户何时退出我的应用程序,那可能会很酷

【问题讨论】:

  • 你读过注意点吗? ①Flutter端widget的生命周期方法调用均由宿主应用端进行。应用突然关闭后,flutter 终端将不再收到任何消息。 ②Flutter端的根页面正常关闭时,State#dispose方法没有被提升,所以我们的onDestroy方法也没有被提升,所以要释放资源,就得自己动手了。
  • 啊,是的!对于这个问题,您还有其他解决方案吗?
  • 这取决于您在退出应用程序时究竟想做什么。
  • 执行函数删除firebase上的文档
  • 我也想在退出应用程序时删除 Firebase 文档。你解决了吗?

标签: flutter state destroy


【解决方案1】:

无论如何,您现在不能完全按照您的意愿去做,目前最好的方法是使用 SDK 中的 AppLifecycleState 检查应用程序何时在后台运行/处于非活动状态(基本上可以执行您的库尝试执行的操作)做)

您使用的库已过时,因为从 2019 年 11 月的拉取请求 AppLifecycleState.suspending 它被称为 AppLifecycleState.detached

您可以查看api.flutter.dev 网站中的 AppLifecycleState 枚举

这是一个如何观察包含活动的生命周期状态的示例:

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

我认为在非活动周期中删除您的数据,然后在恢复的周期中再次创建它可以为您工作。

【讨论】:

  • 该代码是因为他可以看到状态如何工作以及如何使用生命周期的事件来调用他的函数,可能会在暂停的周期中删除他的数据,然后在恢复的周期中再次创建它.这也是他尝试使用的库的 SDK 方式。
  • 暂停!= 退出应用
  • 这是最接近他想要做的方式,我编辑了帖子,因为他会发现这不是他所要求的,但这是目前唯一的方法。
【解决方案2】:

audio_service 插件做了非常相似的事情。该策略是将您的应用程序包装在一个自定义小部件中,该小部件会监听应用程序生命周期状态何时发生变化,然后根据状态运行不同的代码。我并不是说你应该使用这个插件,而是你可以调整代码以满足你的需要。将下面对AudioService 的引用替换为您需要运行的任何代码。

这里是the code from audio_service

/// A widget that maintains a connection to [AudioService].
///
/// Insert this widget at the top of your `/` route's widget tree to maintain
/// the connection across all routes. e.g.
///
/// ```
/// return MaterialApp(
///   home: AudioServiceWidget(MainScreen()),
/// );
/// ```
///
/// Note that this widget will not work if it wraps around [MateriaApp] itself,
/// you must place it in the widget tree within your route.
class AudioServiceWidget extends StatefulWidget {
  final Widget child;

  AudioServiceWidget({@required this.child});

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

class _AudioServiceWidgetState extends State<AudioServiceWidget>
    with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    AudioService.connect();
  }

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

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.resumed:
        AudioService.connect();
        break;
      case AppLifecycleState.paused:
        AudioService.disconnect();
        break;
      default:
        break;
    }
  }

  @override
  Future<bool> didPopRoute() async {
    AudioService.disconnect();
    return false;
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}

注意

  • 对于大多数用户来说,退出应用程序通常只是意味着隐藏它。该应用在后台仍处于活动状态,直到系统将其终止以节省资源。

【讨论】:

    【解决方案3】:

    将你的 main/home/top Scaffold 小部件放在 WillPopScope 中怎么样?

    class MyGreatestApp extends StatefulWidget {
      @override
      _MyGreatestAppState createState() => _MyGreatestAppState();
    }
    
    class _MyGreatestAppState extends State<MyGreatestApp> {
      @override
      Widget build(BuildContext context) {
        return WillPopScope(
          child: Scaffold(...),
          onWillPop: _doNastyStuffsBeforeExit,
        );
      }
    
      Future<bool> _doNastyStuffsBeforeExit() async{
        // Since this is an async method, anything you do here will not block UI thread
        // So you should inform user there is a work need to do before exit, I recommend SnackBar
    
        // Do your pre-exit works here...
    
        // also, you must decide whether the app should exit or not after the work above, by returning a future boolean value:
    
        return Future<bool>.value(true); // this will close the app,
        return Future<bool>.value(false); // and this will prevent the app from exiting (by tapping the back button on home route)
      }
    }
    

    【讨论】:

    • 请注意,WillPopScope 具有禁用 iOS 上“滑动返回”手势的效果,这可能不是我们想要的。此行为也是设计使然(请参阅github.com/flutter/flutter/issues/14203)。相反,您可以使用 WidgetsBindingObserver.didPopRoute ,因为这有点低级别(请参阅 Suragch 的答案以获取示例)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-29
    • 2016-12-23
    相关资源
    最近更新 更多