Android API<25使用MediaProjection截图空指针异常问题求助
Alright, let's fix this issue for you. First, that NullPointerException is happening because your screenshotPermission Intent is null—you can't call clone() on a null object, which makes total sense. Here's what's wrong and how to fix it properly for API <25, plus a solution for the video black screen problem:
1. Root Cause of the NPE
To use MediaProjection, you must first request user permission via the system's consent dialog—you can't skip this step and try to use an uninitialized Intent. The system only returns a valid permission Intent after the user grants access, so your current code is trying to clone a null value, hence the crash.
2. Step-by-Step Fix for API <25 Screenshots
First: Trigger the MediaProjection Permission Request
Add this code where you want to start the screenshot flow (e.g., a button click):
private static final int REQUEST_MEDIA_PROJECTION = 1001; private Intent screenshotPermission; // Will hold the permission Intent after user consent // Call this method to start the permission flow private void requestScreenCapturePermission() { MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION); }
Second: Handle the Permission Result
Override onActivityResult to capture the valid permission Intent once the user grants access:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_MEDIA_PROJECTION && resultCode == RESULT_OK) { screenshotPermission = data; // Save the permission Intent here // Now proceed with the actual screenshot captureScreenWithMediaProjection(); } }
Third: Implement the Screenshot Logic (With Async Handling)
The ImageReader captures frames asynchronously—you can't call acquireLatestImage() immediately after creating the virtual display. Use a listener to get notified when a frame is ready:
private MediaProjection mediaProjection; private ImageReader mImageReader; private Bitmap image; private Handler mHandler = new Handler(Looper.getMainLooper()); private void captureScreenWithMediaProjection() { if (screenshotPermission == null) return; final DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); final int width = metrics.widthPixels; final int height = metrics.heightPixels; final int densityDpi = metrics.densityDpi; final int MAX_IMAGES = 10; MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); try { // Now clone the valid permission Intent mediaProjection = mediaProjectionManager.getMediaProjection(RESULT_OK, (Intent) screenshotPermission.clone()); mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, MAX_IMAGES); // Set listener to handle captured frames mImageReader.setOnImageAvailableListener(reader -> { // Use try-with-resources to auto-close the Image try (Image img = reader.acquireLatestImage()) { if (img != null) { byte[] datamm = Utils.getDataFromImage(img); image = BitmapFactory.decodeByteArray(datamm, 0, datamm.length); // Resize the bitmap after successful capture image = Utils.getResizedBitmap(image, 500); // Do your work with the screenshot bitmap here (e.g., save, send) // Clean up resources to avoid leaks mediaProjection.stop(); mImageReader.close(); } } catch (Exception e) { e.printStackTrace(); } }, mHandler); // Create virtual display with flags to fix video black screen mediaProjection.createVirtualDisplay("ScreenCapture", width, height, densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader.getSurface(), null, null); } catch (Exception e) { e.printStackTrace(); } }
3. Fixing the Video Black Screen Issue
The black screen when capturing video is usually caused by incorrect virtual display flags. Use VIRTUAL_DISPLAY_FLAG_PUBLIC alongside AUTO_MIRROR—this ensures the virtual display can capture content from surface views (like video players) that use secure rendering surfaces. Also, waiting for the onImageAvailable callback ensures you only capture the frame once it's fully rendered.
4. Additional Best Practices
- Always clean up resources: Call
mediaProjection.stop()andmImageReader.close()after you're done with the screenshot to prevent memory leaks. - For API 26+, your existing
PixelCopycode should work, but if you still get black screens for video, confirm you're capturing the correct window (some video players render outside the activity window, so you might need to adjust yourPixelCopytarget).
内容的提问来源于stack exchange,提问作者ridvan




