When developing an Android application using Kotlin, many developers face a common issue: the app does not save images to the device gallery. This problem can occur due to missing permissions, incorrect file paths, or changes in Android storage policies (especially from Android 10 and above with Scoped Storage).
In this article, we will go through step-by-step solutions on how to fix the issue of Kotlin app not saving image to gallery. We will provide a complete example with source code and explain how to properly request permissions, save images, and make them visible in the gallery.

1. Why Images Don’t Appear in Gallery
There are several reasons why your image might not show up in the gallery:
- Missing Storage Permission: On Android 9 and below, WRITE_EXTERNAL_STORAGE is required.
- Scoped Storage: Starting from Android 10, apps must use
MediaStore
API instead of directly writing to external storage. - No Media Scanner Update: The gallery app relies on the system media scanner. If the image is not scanned, it won’t appear.
- Wrong File Path: Saving to a non-public directory prevents gallery apps from detecting the file.
2. Request Necessary Permissions
Before saving an image, you must ensure the app has the correct permissions. Add this to your AndroidManifest.xml
:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Note: From Android 10 (API 29), WRITE_EXTERNAL_STORAGE is deprecated. You should use the MediaStore
API.
3. Kotlin Example: Saving Image to Gallery
The following Kotlin code snippet shows how to save a Bitmap image to the gallery properly:
fun saveImageToGallery(context: Context, bitmap: Bitmap, title: String) { val filename = "$title.jpg" val fos: OutputStream? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val resolver = context.contentResolver val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, filename) put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES) } val imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues) fos = imageUri?.let { resolver.openOutputStream(it) } } else { val imagesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) val image = File(imagesDir, filename) fos = FileOutputStream(image) // Inform Media Scanner about the new file context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(image))) } fos?.use { bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it) } }
This function automatically detects whether the device is running Android Q (10) or higher and uses MediaStore
. On older devices, it writes directly to external storage and triggers a media scan broadcast.
4. Example Use Case
Let’s say you want to save an image captured from the camera or generated in your app. Here’s a complete example inside an Activity:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val bitmap = BitmapFactory.decodeResource(resources, R.drawable.sample_image) val saveButton = findViewById<Button>(R.id.saveButton) saveButton.setOnClickListener { saveImageToGallery(this, bitmap, "MySavedImage") Toast.makeText(this, "Image Saved to Gallery", Toast.LENGTH_SHORT).show() } } }
After running this code, the image should appear in the gallery. If it does not, make sure you:
- Granted the necessary storage permissions (on devices < Android 10).
- Use
MediaStore
API for Android 10 and above. - Check device storage settings and gallery refresh.
5. Comparison: Direct File Save vs MediaStore API
The following table compares the old method (direct save) with the modern method (MediaStore
):
Method | Supported Android Version | Pros | Cons |
---|---|---|---|
Direct File Save | Android 9 and below | Simple, direct access to external storage | Deprecated, requires extra permissions, not working on Android 10+ |
MediaStore API | Android 10 and above | Secure, no WRITE_EXTERNAL_STORAGE permission needed | More complex implementation |
6. Common Mistakes and Fixes
- Forgetting Media Scanner: Without scanning, gallery won’t update. Always use
MediaStore
insert orIntent.ACTION_MEDIA_SCANNER_SCAN_FILE
. - Wrong File Format: Make sure you save as JPG or PNG with correct MIME type.
- Saving to Private Directory: Images saved in app private folder won’t be visible in gallery.
7. Conclusion
If your Kotlin app is not saving images to the gallery, the issue is usually related to permissions or incorrect storage API usage. By following the code above and using the MediaStore
API for Android 10+, you can ensure images are correctly saved and visible in the gallery across all devices.
This guide provided both code snippets and troubleshooting tips to help you resolve the issue permanently. Whether you are building a camera app, photo editor, or social media application, applying these practices will guarantee smooth saving of images to the user’s gallery.