部分设备上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
相关产品推荐
相关产品推荐

