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

Android SDK中Flutter模块启动崩溃:缓存FlutterEngine不存在问题

解决FlutterEngineCache中请求的引擎不存在的偶现崩溃问题

问题概述

启动多模块Flutter SDK时出现偶现崩溃,Firebase显示约0.1%用户触发,错误信息:

Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{package/io.flutter.embedding.android.FlutterActivity}: java.lang.IllegalStateException: The requested cached FlutterEngine did not exist in the FlutterEngineCache: 'my_engine_id'

当前代码逻辑为切换模块时先清空引擎缓存再创建新引擎,以此避免回到首次打开的模块;同时使用缓存引擎解决启动短暂空白屏问题。

崩溃原因分析

  1. 多线程竞争:FlutterEngineCache是全局单例,但缓存的clear、put操作未加同步保护,多线程同时调用启动逻辑时,会出现缓存被意外清除的情况,导致后续启动Activity时找不到引擎。
  2. 生命周期未绑定:创建的FlutterEngine未关联Activity生命周期,可能被系统回收或在缓存操作完成前意外销毁。
  3. 检查与使用的时间窗口漏洞:缓存存在性检查完成后,到启动FlutterActivity的间隙,可能有其他操作移除了缓存引擎,导致最终启动时引擎不存在。

修复方案

1. 给缓存操作添加同步锁

确保缓存的clear、put、contains操作原子性,避免多线程竞争:

// 定义全局锁对象
private val engineCacheLock = Any()

// 修改缓存操作代码
synchronized(engineCacheLock) {
    FlutterEngineCache.getInstance().clear()
    FlutterEngineCache.getInstance().put(ENGINE_ID, instance!!.flutterEngine)
    GeneratedPluginRegister.registerGeneratedPlugins(instance!!.flutterEngine)
}

// 检查缓存时同步加锁
synchronized(engineCacheLock) {
    if (baseActivity == null || !FlutterEngineCache.getInstance().contains(ENGINE_ID)) {
        FirebaseCrashlytics.getInstance().recordException(Throwable("Engine Id not found"))
        return false
    }
}

2. 绑定FlutterEngine到Activity生命周期

避免引擎被意外回收,同时在Activity销毁时清理缓存和引擎:

if (activity != null) {
    instance!!.flutterEngine = FlutterEngine(activity)
    // 绑定生命周期,在Activity销毁时清理资源
    activity.lifecycle.addObserver(object : DefaultLifecycleObserver {
        override fun onDestroy(owner: LifecycleOwner) {
            super.onDestroy(owner)
            synchronized(engineCacheLock) {
                FlutterEngineCache.getInstance().remove(ENGINE_ID)
            }
            instance!!.flutterEngine.destroy()
        }
    })
} else {
    val appContext = MyApplication.getInstance().currentActivity.applicationContext
    instance!!.flutterEngine = FlutterEngine(appContext)
}

3. 优化模块切换逻辑,避免频繁清空缓存

当前清空全局缓存的逻辑是崩溃诱因之一,可通过两种方式优化:

  • 方案A:复用引擎,传递模块参数切换页面
    不需要清空缓存,复用已有引擎并向Dart侧传递模块参数,由Dart代码切换对应模块页面:

    // 复用引擎,执行Dart入口并传递模块参数
    instance!!.flutterEngine.dartExecutor.executeDartEntrypoint(
        DartExecutor.DartEntrypoint.createDefault(),
        arrayOf(moduleName)
    )
    // 初始化对应模块的平台通道
    when (moduleName) {
        Constant.MODULE1 -> Module1PlatformChannels(instance!!.flutterEngine, baseActivity!!).init()
        Constant.MODULE2 -> Module2PlatformChannels(instance!!.flutterEngine, baseActivity!!).init()
    }
    

    Dart侧接收参数初始化对应模块:

    void main(List<String> args) {
      String initialModule = args.isNotEmpty ? args[0] : Constant.MODULE1;
      runApp(MyApp(initialModule: initialModule));
    }
    
  • 方案B:为不同模块分配独立引擎ID
    每个模块使用专属引擎ID,避免清空全局缓存:

    // 生成模块专属引擎ID
    private fun getEngineId(moduleName: String) = "engine_$moduleName"
    
    val engineId = getEngineId(moduleName)
    synchronized(engineCacheLock) {
        if (!FlutterEngineCache.getInstance().contains(engineId)) {
            val engine = FlutterEngine(activity ?: MyApplication.getInstance().currentActivity.applicationContext)
            engine.dartExecutor.executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault())
            FlutterEngineCache.getInstance().put(engineId, engine)
            GeneratedPluginRegister.registerGeneratedPlugins(engine)
        }
    }
    // 初始化对应模块通道
    when (moduleName) {
        Constant.MODULE1 -> Module1PlatformChannels(FlutterEngineCache.getInstance().get(engineId)!!, baseActivity!!).init()
        Constant.MODULE2 -> Module2PlatformChannels(FlutterEngineCache.getInstance().get(engineId)!!, baseActivity!!).init()
    }
    // 启动对应缓存引擎的FlutterActivity
    return FlutterActivity.withCachedEngine(engineId).build(context)
    

4. 增加启动前二次兜底检查

在构建FlutterActivity Intent前再次确认引擎存在,避免检查与启动之间的间隙出现异常:

val intent = synchronized(engineCacheLock) {
    if (!FlutterEngineCache.getInstance().contains(ENGINE_ID)) {
        // 兜底重建引擎并放入缓存
        instance!!.flutterEngine = FlutterEngine(activity ?: MyApplication.getInstance().currentActivity.applicationContext)
        instance!!.flutterEngine.dartExecutor.executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault())
        FlutterEngineCache.getInstance().put(ENGINE_ID, instance!!.flutterEngine)
        GeneratedPluginRegister.registerGeneratedPlugins(instance!!.flutterEngine)
    }
    FlutterActivity.withCachedEngine(ENGINE_ID).build(context)
}
return intent

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 14:05:34