MediaStore.Images.Media.insertImage已废弃,如何用MediaColumns#IS_PENDING存图片?
MediaColumns.IS_PENDING to Replace Deprecated insertImage() Great question—this is a super common point of confusion when ditching the old insertImage() method. Let’s break down exactly how to use MediaColumns.IS_PENDING (yes, you absolutely need to pair it with ContentValues) to safely save images to MediaStore.
Core Idea Behind IS_PENDING
MediaColumns.IS_PENDING is a flag that controls your media file’s visibility and accessibility during the save workflow:
- Set it to
1when you first insert the media record: This marks the file as "pending," so other apps can’t see or access it while you’re writing the actual image data (no more half-written files being picked up by gallery apps!). - Set it to
0once you’ve finished writing: This unlocks the file, making it visible and accessible to all apps—just like the oldinsertImage()did.
Step-by-Step Implementation
Here’s a complete, practical example (Kotlin included; Java logic is nearly identical):
Create Initial ContentValues & Insert a Pending Record
First, define your image’s metadata (name, MIME type, save location) and mark it as pending. Insert this into MediaStore to get aUriyou can write to.Write the Image Data
Use theUrifrom step 1 to open an output stream and write your bitmap or raw image bytes.Mark the File as Complete
Update the record to setIS_PENDINGto0, making it visible to other apps.
Full Code Example
fun saveImageToMediaStore( context: Context, bitmap: Bitmap, displayName: String, mimeType: String = "image/png" ): Uri? { val contentValues = ContentValues().apply { // Basic image metadata put(MediaStore.Images.Media.DISPLAY_NAME, displayName) put(MediaStore.Images.Media.MIME_TYPE, mimeType) // Save to a custom subfolder in Pictures (optional but keeps your files organized) put(MediaStore.Images.Media.RELATIVE_PATH, "${Environment.DIRECTORY_PICTURES}/MyAppImages") // Mark as pending to block other apps from accessing incomplete data put(MediaColumns.IS_PENDING, 1) } val contentResolver = context.contentResolver var imageUri: Uri? = null try { // Insert the pending record into MediaStore imageUri = contentResolver.insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues ) ?: throw IOException("Failed to create MediaStore record") // Write the bitmap data to the Uri contentResolver.openOutputStream(imageUri)?.use { outputStream -> if (!bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)) { throw IOException("Failed to compress and write bitmap") } } ?: throw IOException("Could not open output stream for image Uri") // Mark the image as complete (no longer pending) contentValues.clear() contentValues.put(MediaColumns.IS_PENDING, 0) contentResolver.update(imageUri, contentValues, null, null) } catch (e: IOException) { // Clean up if something goes wrong: delete the incomplete record to avoid ghost entries imageUri?.let { contentResolver.delete(it, null, null) } e.printStackTrace() } return imageUri }
Key Notes
- Error Handling: Always clean up the pending record if writing fails—otherwise you’ll leave a useless entry in MediaStore that takes up space.
- Permissions: On Android 10 (API 29) and above, you don’t need the
WRITE_EXTERNAL_STORAGEpermission for saving to standard directories likeDIRECTORY_PICTURES. For older versions, you’ll still need to request it. - Flexibility: This approach gives you way more control than
insertImage()—you can set custom paths, add extra metadata, or even pause/resume the write process (by keepingIS_PENDINGset to 1 until you’re fully done).
内容的提问来源于stack exchange,提问作者apksherlock

