Android中使用Media Projection API投射的画面无法显示在SurfaceView悬浮窗上
看起来你已经把基础的权限、前台服务配置都做了,但投射画面就是不显示,这种没报错的问题确实挺头疼的。我结合你的代码梳理几个可能的关键点,你可以逐一排查试试:
1. Surface与MediaProjection的初始化时机不匹配
你的代码里,在onStartCommand拿到MediaProjection后,会直接检查mSurface != null就启动录屏,但windowManager.addView(view, params)是异步执行的,SurfaceHolder的surfaceCreated回调可能还没触发——这时候你拿到的mSurface其实是未初始化的空对象,自然无法渲染画面。
调整方案:
- 新增一个布尔变量
mSurfaceReady标记Surface是否准备完成 - 在
surfaceCreated回调里标记Surface就绪,同时检查MediaProjection是否已拿到,若已拿到则启动录屏:
private boolean mSurfaceReady = false; // 在setupOverlay的SurfaceHolder.Callback中 @Override public void surfaceCreated(SurfaceHolder holder) { mSurface = holder.getSurface(); mSurfaceReady = true; if (mMediaProjection != null) { startScreenCapture(); } }
- 在
onStartCommand拿到MediaProjection后,检查Surface是否就绪,再启动录屏:
mMediaProjection = mediaProjectionManager.getMediaProjection(rc, d); if (mMediaProjection != null && mSurfaceReady) { startScreenCapture(); }
2. VirtualDisplay的参数可能存在问题
你创建VirtualDisplay时用了DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,这个标记在某些场景下可能会导致投射逻辑异常;另外固定的900x500尺寸要确保和SurfaceView的实际显示尺寸完全匹配。
调整方案:
把标记换成DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,同时确认尺寸参数和悬浮窗一致:
mVirtualDisplay = mMediaProjection.createVirtualDisplay( "ScreenCapture", 900, 500, getResources().getDisplayMetrics().densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, // 替换为这个标记 mSurface, null, null );
3. SurfaceView的像素格式可能不兼容
你设置的PixelFormat.OPAQUE可能会和MediaProjection的渲染格式冲突,导致画面无法显示。
调整方案:
修改悬浮窗LayoutParams的像素格式为PixelFormat.RGBA_8888:
WindowManager.LayoutParams params = new WindowManager.LayoutParams( 900, 500, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.RGBA_8888 // 更换像素格式 );
4. 新增日志排查VirtualDisplay创建状态
虽然没有报错日志,但可以手动添加日志确认VirtualDisplay是否成功创建:
public void startScreenCapture() { // ... 原有代码 mVirtualDisplay = mMediaProjection.createVirtualDisplay(...); if (mVirtualDisplay == null) { Log.e("ScreenCapture", "VirtualDisplay创建失败!"); } else { Log.d("ScreenCapture", "VirtualDisplay创建成功"); } }
关于TextureView的补充尝试
你之前换TextureView没效果,可能是因为TextureView的使用逻辑和SurfaceView不同,需要设置SurfaceTextureListener来获取Surface:
// 假设screenMirror是TextureView screenMirror.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { mSurface = new Surface(surfaceTexture); mSurfaceReady = true; if (mMediaProjection != null) { startScreenCapture(); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {} @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { mSurface.release(); return true; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {} });
你可以先从「时机匹配」这个点入手调整,这是这类问题最常见的原因。
内容来源于stack exchange

