You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter应用关闭前如何保存数据?需Kotlin与Swift原生示例

解决Flutter应用被杀死前保存状态的问题

问题分析

当用户通过安卓应用概览上滑关闭、iOS应用切换界面划掉应用时,Flutter的detached生命周期状态、Android的onDestroy()方法大概率不会触发——因为系统可能直接终止进程,不会执行这些常规生命周期回调。要实现"被杀死前保存最后访问页面和时间"的需求,需要依赖原生平台的后台状态监听机制,在应用进入后台时完成状态保存(这是系统一定会触发的回调,同时覆盖进程被杀死的场景)。

Android端实现(Kotlin)

安卓可以通过ProcessLifecycleOwner监听整个应用的生命周期,在应用退到后台时执行保存操作,同时可结合内存回收回调补充覆盖极端场景。

1. 添加依赖

在app/build.gradle的dependencies块中添加:

implementation "androidx.lifecycle:lifecycle-process:2.6.2"

2. 实现应用生命周期监听

自定义Application类并注册监听:

import android.app.Application
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.dart.DartExecutor
import io.flutter.plugin.common.MethodChannel
import java.text.SimpleDateFormat
import java.util.*

class MyApp : Application(), LifecycleObserver {
    private val CHANNEL = "app_state_channel"
    private var currentPage = "home_page"

    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
        
        // 初始化MethodChannel,接收Flutter传递的当前页面信息
        val flutterEngine = FlutterEngine(this)
        flutterEngine.dartExecutor.executeDartEntrypoint(
            FlutterEngine.DartEntrypoint.createDefault()
        )
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "setCurrentPage") {
                currentPage = call.argument<String>("page") ?: "home_page"
                result.success(null)
            } else {
                result.notImplemented()
            }
        }
    }

    // 应用退到后台时触发
    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onAppBackgrounded() {
        saveAppState()
    }

    // 系统内存不足、即将杀死进程时触发(补充场景)
    override fun onTrimMemory(level: Int) {
        super.onTrimMemory(level)
        if (level == TRIM_MEMORY_COMPLETE) {
            saveAppState()
        }
    }

    private fun saveAppState() {
        val closeTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())
        
        // 保存到SharedPreferences(也可替换为数据库操作,注意轻量化)
        val sharedPref = getSharedPreferences("AppState", MODE_PRIVATE)
        with(sharedPref.edit()) {
            putString("last_page", currentPage)
            putString("close_time", closeTime)
            apply() // 用apply()避免阻塞主线程
        }
    }
}

别忘了在AndroidManifest.xml中指定自定义Application:

<application
    android:name=".MyApp"
    ...>
</application>

iOS端实现(Swift)

iOS在应用进入后台时会触发sceneDidEnterBackground(iOS13+)或applicationDidEnterBackground(iOS12及以下)回调,可在此完成状态保存。

iOS13+ 实现(SceneDelegate)

import UIKit
import Flutter

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?
    private let CHANNEL = "app_state_channel"
    private var currentPage = "home_page"

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        
        // 初始化Flutter引擎与MethodChannel
        let flutterEngine = FlutterEngine(name: "MyFlutterEngine")
        flutterEngine.run()
        GeneratedPluginRegistrant.register(with: flutterEngine)
        
        let channel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: flutterEngine.binaryMessenger)
        channel.setMethodCallHandler { [weak self] call, result in
            guard let self = self else { return }
            if call.method == "setCurrentPage" {
                if let args = call.arguments as? [String: String], let pageName = args["page"] {
                    self.currentPage = pageName
                }
                result.success(nil)
            } else {
                result.notImplemented()
            }
        }
        
        window = UIWindow(windowScene: windowScene)
        window?.rootViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
        window?.makeKeyAndVisible()
    }

    // 应用退到后台时触发
    func sceneDidEnterBackground(_ scene: UIScene) {
        saveAppState()
    }

    private func saveAppState() {
        let closeTime = DateFormatter.localizedString(from: Date(), dateStyle: .medium, timeStyle: .medium)
        
        // 保存到UserDefaults(也可替换为数据库操作)
        UserDefaults.standard.set(currentPage, forKey: "last_page")
        UserDefaults.standard.set(closeTime, forKey: "close_time")
        UserDefaults.standard.synchronize()
    }
}

iOS12及以下兼容(AppDelegate)

import UIKit
import Flutter

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    private let CHANNEL = "app_state_channel"
    private var currentPage = "home_page"

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        let flutterEngine = FlutterEngine(name: "MyFlutterEngine")
        flutterEngine.run()
        GeneratedPluginRegistrant.register(with: flutterEngine)
        
        let channel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: flutterEngine.binaryMessenger)
        channel.setMethodCallHandler { [weak self] call, result in
            guard let self = self else { return }
            if call.method == "setCurrentPage" {
                if let args = call.arguments as? [String: String], let pageName = args["page"] {
                    self.currentPage = pageName
                }
                result.success(nil)
            } else {
                result.notImplemented()
            }
        }
        
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
        window?.makeKeyAndVisible()
        return true
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        saveAppState()
    }

    private func saveAppState() {
        let closeTime = DateFormatter.localizedString(from: Date(), dateStyle: .medium, timeStyle: .medium)
        UserDefaults.standard.set(currentPage, forKey: "last_page")
        UserDefaults.standard.set(closeTime, forKey: "close_time")
        UserDefaults.standard.synchronize()
    }
}

Flutter端配合代码

通过MethodChannel向原生传递当前页面信息,在每个页面的initState中调用:

import 'package:flutter/services.dart';

class PageStateManager {
  static const MethodChannel _channel = MethodChannel('app_state_channel');

  static Future<void> sendCurrentPage(String pageName) async {
    try {
      await _channel.invokeMethod('setCurrentPage', {'page': pageName});
    } on PlatformException catch (e) {
      print("Failed to send page info: ${e.message}");
    }
  }
}

// 示例页面调用
class HomePage extends StatefulWidget {
  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  void initState() {
    super.initState();
    PageStateManager.sendCurrentPage('home_page');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(appBar: AppBar(title: const Text("Home")));
  }
}

关键注意事项

  • 不要依赖detached、onDestroy()或applicationWillTerminate,这些回调在进程被强制杀死时大概率不会执行。
  • 保存操作必须轻量化,避免耗时IO操作,否则可能被系统终止或引发ANR(安卓)。
  • 优先在应用进入后台时保存状态,既覆盖进程被杀死的场景,也能在正常退后台时保存最新状态,提升用户恢复体验。

内容的提问来源于stack exchange,提问作者Ibne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 23:03:16