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

ML-Kit文档扫描器打开时无法获取应用生命周期回调问题

ML-Kit文档扫描器后台切换时生命周期回调失效的解决方案

问题根源

ML-Kit的文档扫描器实际启动的是Google Play服务提供的独立Activity,不属于你的App包名/进程范畴。这会导致两个问题:

  • 宿主Activity被扫描器界面覆盖,但并未真正进入onStopped()状态,所以ActivityLifecycleCallbacks的回调不会触发
  • 默认的AppLifecycleObserver会把第三方Activity的启动算入App的Activity计数,导致打开扫描器时误判为进入后台,而真正切后台时计数未归0,无法触发onEnterBackground

可行解决方案

1. 绑定扫描器的返回结果主动处理

利用Activity Result API的回调,不管扫描成功还是取消,都直接执行Utils.removeWindowManager(),完全绕开生命周期的问题:

// 注册扫描器的Activity Result回调
val documentScannerLauncher = registerForActivityResult(ScanDocumentContract()) { result ->
    // 无论扫描结果如何,都执行Window移除操作
    Utils.removeWindowManager(baseContext)
    
    // 正常处理扫描结果
    result?.let {
        // 处理扫描得到的文档...
    }
}

// 启动扫描器
documentScannerLauncher.launch(ScanDocumentOptions.Builder().build())

2. 修正AppLifecycleObserver的Activity计数逻辑

自定义Application.ActivityLifecycleCallbacks,只统计当前App包名的Activity数量,避免被第三方Activity干扰:

class CustomAppLifecycleObserver(private val context: Context) : Application.ActivityLifecycleCallbacks {
    private var appActivityCount = 0

    override fun onActivityStarted(activity: Activity) {
        // 仅统计当前App的Activity
        if (activity.packageName == context.packageName) {
            appActivityCount++
            if (appActivityCount == 1) {
                // App进入前台,可做对应处理
            }
        }
    }

    override fun onActivityStopped(activity: Activity) {
        if (activity.packageName == context.packageName) {
            appActivityCount--
            if (appActivityCount == 0) {
                // App真正进入后台,执行Window移除
                Utils.removeWindowManager(context)
            }
        }
    }

    // 实现其他空回调方法
    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) = Unit
    override fun onActivityResumed(activity: Activity) = Unit
    override fun onActivityPaused(activity: Activity) = Unit
    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit
    override fun onActivityDestroyed(activity: Activity) = Unit
}

// 在Application的onCreate中注册
registerActivityLifecycleCallbacks(CustomAppLifecycleObserver(this))

3. 监听当前Window的焦点变化

给宿主Activity的Window添加焦点监听,当窗口失去焦点且App确实进入后台时,执行移除操作:

// 在Activity的onCreate中设置
window.onWindowFocusChangeListener = { hasFocus ->
    if (!hasFocus && isScannerActive && isAppInBackground()) {
        Utils.removeWindowManager(baseContext)
    }
}

// 标记扫描器是否处于激活状态
private var isScannerActive = false

// 启动扫描器时标记状态
documentScannerLauncher.launch(ScanDocumentOptions.Builder().build())
isScannerActive = true

// 辅助方法:判断App是否处于后台
private fun isAppInBackground(): Boolean {
    val am = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    am.runningAppProcesses?.forEach { processInfo ->
        if (processInfo.processName == packageName) {
            return processInfo.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
        }
    }
    return false
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 21:32:21