Android平台下如何获取包含Dialog与Toast在内全部界面元素的像素位图?
Great question! You’re totally right that PixelCopy and Canvas-based screenshot methods only capture your Activity’s DecorView—they completely miss floating elements like Toasts, AlertDialogs, or even system overlays like the status bar. To grab a full, true-to-visual screenshot of everything visible on the screen, the official (and reliable) approach is to use the MediaProjection API, introduced in Android 5.0 (API level 21).
How It Works
The MediaProjection API lets your app request permission to capture the entire screen, including all system and app-level overlays. Here’s a step-by-step breakdown:
Request Screen Capture Permission
First, you need to ask the user for explicit permission to capture the screen via a system dialog.private val REQUEST_CODE_SCREEN_CAPTURE = 100 fun startScreenCaptureFlow() { val mediaProjectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager val captureIntent = mediaProjectionManager.createScreenCaptureIntent() startActivityForResult(captureIntent, REQUEST_CODE_SCREEN_CAPTURE) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == REQUEST_CODE_SCREEN_CAPTURE && resultCode == RESULT_OK) { // Permission granted, proceed to capture the screen captureFullScreen(data!!) } }Capture the Full Screen
Once permission is granted, create aVirtualDisplaythat mirrors the screen, then use anImageReaderto capture frame data and convert it to a Bitmap.private fun captureFullScreen(permissionData: Intent) { val mediaProjectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager val mediaProjection = mediaProjectionManager.getMediaProjection(RESULT_OK, permissionData) val displayMetrics = resources.displayMetrics val screenWidth = displayMetrics.widthPixels val screenHeight = displayMetrics.heightPixels val imageReader = ImageReader.newInstance(screenWidth, screenHeight, ImageFormat.RGB_565, 1) val virtualDisplay = mediaProjection.createVirtualDisplay( "FullScreenCapture", screenWidth, screenHeight, displayMetrics.densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, imageReader.surface, null, null ) // Wait a short time for the display to stabilize before capturing Handler(Looper.getMainLooper()).postDelayed({ val image = imageReader.acquireLatestImage() image?.let { val planes = it.planes val buffer = planes[0].buffer val pixelStride = planes[0].pixelStride val rowStride = planes[0].rowStride val rowPadding = rowStride - pixelStride * screenWidth // Generate the full-screen bitmap val fullScreenBitmap = Bitmap.createBitmap( screenWidth + rowPadding / pixelStride, screenHeight, Bitmap.Config.RGB_565 ) fullScreenBitmap.copyPixelsFromBuffer(buffer) // Now you have the complete screen bitmap (Toasts, Dialogs included!) // Use it as needed: save to file, display in a View, etc. image.close() mediaProjection.stop() virtualDisplay.release() } }, 500) }
Key Considerations
- Permission Durability: The MediaProjection permission is temporary—you’ll need to re-request it if the app restarts or the device reboots.
- Foreground Requirement: On Android 10 (API 29) and later, your app must be running in the foreground (with a visible activity or foreground service) to use this API.
- Performance: Screen captures are resource-heavy, so avoid frequent captures if possible to prevent lag.
- Root Workarounds: While rooted devices let you read directly from the system framebuffer, this is highly unportable and not recommended for production apps.
MediaProjection is the only official, non-root way to capture every visible element on the screen—including Toasts, Dialogs, and system UI. It’s the standard approach used by most screen recording and screenshot apps on the Play Store.
内容的提问来源于stack exchange,提问作者jay

