API 33下使用ActivityResultContracts.CaptureVideo()触发DeadObjectException崩溃
问题
使用ActivityResultContracts.CaptureVideo()实现视频拍摄功能时,仅在API 33设备上出现DeadObjectException崩溃,API 32、30、28等低版本运行完全正常。
崩溃堆栈信息
2022-09-19 20:32:02.047 577-601/system_process W/WindowManager: Exception thrown during dispatchAppVisibility Window{5b4304c u0
com.my.package/com.my.package.activities.MainActivity
EXITING}
android.os.DeadObjectException
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(BinderProxy.java:584)
at android.view.IWindow$Stub$Proxy.dispatchAppVisibility(IWindow.java:536)
at com.android.server.wm.WindowState.sendAppVisibilityToClients(WindowState.java:3489)
at com.android.server.wm.WindowContainer.sendAppVisibilityToClients(WindowContainer.java:1199)
at com.android.server.wm.WindowToken.setClientVisible(WindowToken.java:398)
at com.android.server.wm.ActivityRecord.setClientVisible(ActivityRecord.java:6564)
at com.android.server.wm.ActivityRecord.postApplyAnimation(ActivityRecord.java:5280)
at com.android.server.wm.ActivityRecord.commitVisibility(ActivityRecord.java:5235)
at com.android.server.wm.ActivityRecord.commitVisibility(ActivityRecord.java:5239)
at com.android.server.wm.AppTransitionController.handleClosingApps(AppTransitionController.java:1098)
at com.android.server.wm.AppTransitionController.handleAppTransitionReady(AppTransitionController.java:286)
at com.android.server.wm.RootWindowContainer.checkAppTransitionReady(RootWindowContainer.java:975)
at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:842)
at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:784)
at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.os.HandlerThread.run(HandlerThread.java:67)
at com.android.server.ServiceThread.run(ServiceThread.java:44)
实现代码
private fun takeVideo() { val media = File.createTempFile("temp_file", ".mp4", this.requireContext().cacheDir) val fileUri = FileProvider.getUriForFile(this.requireContext(), "${requireContext().packageName}.provider", media) this.fileUri = Uri.parse(media.absolutePath) this.takeVideoResult.launch(fileUri) } /** * A function to handle registering an activity result for video capture */ private val takeVideoResult = registerForActivityResult(ActivityResultContracts.CaptureVideo()) { success -> if (success) { this.fileUri?.let { uri -> this.attachmentUris.add(uri) this.updateAttachmentViews() } } }
分析与解决方案
1. 首要修复:Uri使用逻辑错误
你的代码存在明显的Uri误用问题:传给相机的是FileProvider生成的content格式Uri,但后续保存的却是通过文件绝对路径解析的file格式Uri。API 33对文件权限管控更严格,这种不一致的Uri处理会触发系统窗口管理的异常,这是崩溃的主要诱因。
修复方式:直接保存FileProvider生成的content Uri,不要重新解析文件路径:
private fun takeVideo() { val media = File.createTempFile("temp_file", ".mp4", this.requireContext().cacheDir) val fileUri = FileProvider.getUriForFile(this.requireContext(), "${requireContext().packageName}.provider", media) this.fileUri = fileUri // 直接保留content格式的Uri this.takeVideoResult.launch(fileUri) }
2. API 33系统层面的补充优化
虽然上述修复能解决大部分情况,但API 33初期版本确实存在窗口管理相关的DeadObjectException小概率问题,可补充以下优化:
- 确保
registerForActivityResult在Fragment/Activity的onCreate阶段注册,避免动态注册导致的生命周期不一致。 - 捕获异常做兜底处理:
private val takeVideoResult = registerForActivityResult(ActivityResultContracts.CaptureVideo()) { success -> try { if (success) { this.fileUri?.let { uri -> this.attachmentUris.add(uri) this.updateAttachmentViews() } } } catch (e: DeadObjectException) { Toast.makeText(requireContext(), "拍摄失败,请重试", Toast.LENGTH_SHORT).show() } }
3. 权限检查确认
API 33仍需确保已申请并获得Manifest.permission.CAMERA权限,避免因权限缺失引发连锁异常。
内容的提问来源于stack exchange,提问作者Dwebtron

