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

部分设备上GoogleSignin登录失败,ActivityResult处理器异常求助

问题描述

我实现的ActivityResult处理器在部分生产设备上出现异常,涉及三星等品牌,覆盖Android 10、11、12、13版本,目前找不到问题原因,寻求技术帮助。

代码实现(来自截图)

class TakePhotoResultContract : ActivityResultContract<Void?, Uri?>() {
    private var imageUri: Uri? = null

    override fun createIntent(context: Context, input: Void?): Intent {
        imageUri = createImageUri(context)
        return Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, imageUri)
    }

    override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
        return if (resultCode == Activity.RESULT_OK) imageUri else null
    }

    private fun createImageUri(context: Context): Uri? {
        val contentValues = ContentValues().apply {
            put(MediaStore.Images.Media.DISPLAY_NAME, "IMG_${System.currentTimeMillis()}.jpg")
            put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
            put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/MyApp")
        }
        return context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
    }
}
排查与解决方案建议
  • 解决进程回收导致的Uri丢失:部分设备(尤其是三星)在相机APP启动后,原进程可能被系统回收,此时Contract中持有的imageUri会丢失。可以通过SavedStateHandle或onSaveInstanceState持久化Uri:

    class TakePhotoResultContract : ActivityResultContract<Void?, Uri?>() {
        companion object {
            private const val KEY_IMAGE_URI = "key_take_photo_uri"
        }
    
        override fun createIntent(context: Context, input: Void?): Intent {
            val imageUri = createImageUri(context)
            // 利用SavedState暂存Uri,避免进程回收丢失
            (context as? ComponentActivity)?.run {
                ViewModelProvider(this)[SavedStateViewModel::class.java].saveUri(imageUri)
            }
            return Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, imageUri)
        }
    
        override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
            if (resultCode != Activity.RESULT_OK) return null
            // 从SavedState恢复Uri
            return (intent?.context as? ComponentActivity)?.run {
                ViewModelProvider(this)[SavedStateViewModel::class.java].getSavedUri()
            }
        }
    
        // 原有createImageUri代码不变
    }
    
    class SavedStateViewModel(private val handle: SavedStateHandle) : ViewModel() {
        fun saveUri(uri: Uri?) {
            handle[KEY_IMAGE_URI] = uri?.toString()
        }
    
        fun getSavedUri(): Uri? {
            return handle.get<String>(KEY_IMAGE_URI)?.let { Uri.parse(it) }
        }
    }
    
  • 兼容分区存储的路径差异:部分三星设备对RELATIVE_PATH的解析存在异常,可改用APP私有存储路径(无需额外权限):

    private fun createImageUri(context: Context): Uri? {
        val picDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "MyApp")
        if (!picDir.exists()) picDir.mkdirs()
        val imageFile = File(picDir, "IMG_${System.currentTimeMillis()}.jpg")
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", imageFile)
        } else {
            Uri.fromFile(imageFile)
        }
    }
    

    注意:需在AndroidManifest.xml中配置FileProvider的路径。

  • 兼容第三方相机的返回逻辑:部分第三方相机不遵守EXTRA_OUTPUT约定,会在intent的data字段返回图片Uri,可在parseResult中兼容:

    override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
        if (resultCode != Activity.RESULT_OK) return null
        val savedUri = // 从SavedState恢复的Uri
        return savedUri ?: intent?.data
    }
    
  • 模拟进程回收测试:开启开发者选项中的「不保留活动」,测试拍照流程,复现进程被回收后的场景,验证问题是否在此。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 01:24:52