Get/pick an image from Android's built-in Gallery app programmatically
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
Letting users pick an image from their device is one of the most common features in Android apps, from profile picture selection to photo editing. Android has evolved its approach to this task significantly — from raw intents requiring runtime permissions to a modern photo picker that needs no permissions at all. Understanding both the modern and legacy approaches will help you write code that works correctly across API levels while following current best practices.
The Modern Approach: Photo Picker (Android 13+)
Starting with Android 13 (API 33), Google introduced the Photo Picker, a system-provided UI that lets users select photos and videos without granting your app broad storage permissions. This is the recommended approach for new projects:
For selecting multiple images, use PickMultipleVisualMedia:
The Photo Picker is backported via Google Play Services to devices running Android 4.4 (API 19) and above, so you can use it on most devices in the field today.
Using ActivityResultContracts.GetContent
Before the Photo Picker, the standard modern approach was GetContent, which opens the system file chooser:
This approach still works and is useful when you need to support file types beyond photos and videos, since GetContent accepts any MIME type.
The Legacy Intent Approach
Before the Activity Result API, developers used startActivityForResult with an explicit intent. You may still encounter this pattern in older codebases:
While startActivityForResult is deprecated, the intents themselves still work. The deprecation is about the callback mechanism, not the underlying capability.
Handling the Returned Uri
The Uri you receive from any picker is a content URI, not a file path. You should work with it through ContentResolver rather than trying to convert it to a file path:
For persisting access to the Uri beyond the current activity lifecycle, you need to take persistable permissions:
Permissions: Old vs New
The permission model for accessing images has changed dramatically across Android versions:
The Photo Picker is the clear winner here because it requires zero permissions. The system handles access scoping internally — your app only gets access to the specific files the user selects, nothing more.
Java Example with GetContent
For teams still writing Java, here is the modern approach without the deprecated startActivityForResult:
Common Pitfalls
- Trying to get a file path from a content URI: Content URIs are not file paths. Using
cursor.getString(cursor.getColumnIndex(DATA))is unreliable on modern Android — useContentResolver.openInputStream()instead. - Not handling null URIs: The user can cancel the picker at any time, so the returned Uri will be null. Always check for null before processing.
- Forgetting
maxSdkVersionon legacy permissions: DeclaringREAD_EXTERNAL_STORAGEwithoutmaxSdkVersion="32"will trigger unnecessary permission prompts on Android 13+ devices. - Assuming the Uri persists across app restarts: Content URIs are temporary by default. Call
takePersistableUriPermission()if you need to access the image later, or copy it to your app's private storage. - Loading full-resolution bitmaps into memory: A 12MP photo decoded as a full Bitmap can consume 48MB of heap. Use
BitmapFactory.Options.inSampleSizeor a library like Coil or Glide to load images at the display size.
Summary
- Use
ActivityResultContracts.PickVisualMedia(Photo Picker) for the best user experience with zero permission requirements on Android 13+ and backported to API 19 via Play Services. - Use
ActivityResultContracts.GetContentwhen you need to support non-image file types or cannot rely on the Photo Picker backport. - Avoid the legacy
startActivityForResultpattern in new code — it is deprecated and the Activity Result API is safer and more testable. - Always work with content URIs through
ContentResolverrather than converting them to file paths. - Declare
READ_EXTERNAL_STORAGEwithmaxSdkVersion="32"and useREAD_MEDIA_IMAGESfor API 33+ to follow the modern permission model.
Related reading
- getResources.getColor is deprecated
- getString Outside of a Context or Activity
- getString Outside of a Context or Activity
- Getting a list of files in the Resources folder - iOS
- Getting a This application is modifying the autolayout engine from a background thread error?
- Getting activity from context in android
- Getting all cookies from WKWebView
- Getting and Setting Cursor Position of UITextField and UITextView in Swift
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.