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

Android 12下MediaProjectionManager.getMediaProjection()二次调用报错问题

问题:Android 12(小米11T)截图应用第二次调用MediaProjection时触发空指针异常

我开发的截图应用在多数Android设备上运行正常,但在Android 12的小米11T设备中出现问题:使用静态保存的resultCode和Intent,克隆后传入mediaProjectionManager.getMediaProjection(resultCode, clonedIntent)方法,首次截图正常,第二次截图时触发如下空指针异常:

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.koala.classor, PID: 10824
java.lang.NullPointerException: Attempt to invoke interface method 'boolean java.util.Set.add(java.lang.Object)' on a null object reference
    at android.os.Parcel.createExceptionOrNull(Parcel.java:2431)
    at android.os.Parcel.createException(Parcel.java:2409)
    at android.os.Parcel.readException(Parcel.java:2392)
    at android.os.Parcel.readException(Parcel.java:2334)
    at android.media.projection.IMediaProjection$Stub$Proxy.start(IMediaProjection.java:235)
    at android.media.projection.MediaProjection.<init>(MediaProjection.java:59)
    at android.media.projection.MediaProjectionManager.getMediaProjection(MediaProjectionManager.java:119)
    at com.koala.classor.G.getMediaProjection(G.java:86)
    at com.koala.classor.OverScreenWindowService$2$1.run(OverScreenWindowService.java:194)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:210)
    at android.os.Looper.loop(Looper.java:299)
    at android.app.ActivityThread.main(ActivityThread.java:8105)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)
 Caused by: android.os.RemoteException: Remote stack trace:
    at com.android.server.media.projection.MediaProjectionManagerService$MediaProjection.start(MediaProjectionManagerService.java:553)
    at android.media.projection.IMediaProjection$Stub.onTransact(IMediaProjection.java:137)
    at android.os.Binder.execTransactInternal(Binder.java:1182)
    at android.os.Binder.execTransact(Binder.java:1146)

原因分析

这个异常的核心是MediaProjection的权限Intent只能被使用一次。Android 12及小米MIUI这类定制系统对MediaProjection的权限生命周期管控更严格:第一次调用getMediaProjection后,系统会标记该Intent对应的权限已被消耗,第二次复用(哪怕是克隆)同一个Intent时,系统内部的权限状态已失效,导致服务端抛出空指针。

另外,静态保存resultCode和Intent的方式本身存在风险,应用进程重启或权限状态变更后,这些值会直接失效。


解决步骤

  1. 每次截图前重新申请权限,不复用旧Intent
    放弃静态保存权限参数的方式,每次需要截图时重新启动MediaProjection权限请求流程:

    private static final int REQUEST_CODE_SCREEN_CAPTURE = 1001;
    
    private void requestScreenCapturePermission() {
        MediaProjectionManager manager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
        Intent intent = manager.createScreenCaptureIntent();
        startActivityForResult(intent, REQUEST_CODE_SCREEN_CAPTURE);
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE_SCREEN_CAPTURE && resultCode == RESULT_OK) {
            // 仅在本次截图流程中使用该data,不做静态保存
            MediaProjection projection = mediaProjectionManager.getMediaProjection(resultCode, data);
            performScreenshot(projection);
        }
    }
    
  2. 及时释放MediaProjection资源
    截图完成后立即调用projection.stop()释放资源,避免系统中残留无效实例:

    private void performScreenshot(MediaProjection projection) {
        // 初始化VirtualDisplay、ImageReader等截图组件
        // ... 执行截图逻辑 ...
        // 截图完成后立即释放
        projection.stop();
    }
    
  3. 不要克隆权限Intent
    克隆操作可能丢失系统内部绑定的权限状态信息,直接使用onActivityResult返回的原始data即可,无需额外处理。

  4. 适配Android 12后台权限限制
    Android 12禁止后台应用直接申请MediaProjection权限,确保权限申请操作在应用前台页面触发,不要在后台服务中直接调用。


额外注意事项

  • 若需持续截图(如录屏),可保留同一个MediaProjection实例直到停止操作后再释放,但单次截图必须每次重新申请权限。
  • 小米MIUI系统需确保应用已获得「悬浮窗权限」和「屏幕录制权限」,部分机型需用户手动在设置中开启。

内容的提问来源于stack exchange,提问作者reza r h

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 18:19:47