ContentProviders & Data Sharing
📖 Concept
ContentProviders are Android's standard interface for sharing structured data between apps. They abstract the underlying data storage (SQLite, files, network) behind a content:// URI scheme.
Internal architecture:
- Client app calls ContentResolver.query(uri)
- ContentResolver sends request via Binder IPC to the ContentProvider's process
- ContentProvider processes the request and returns a Cursor
- The Cursor data is transferred back via Binder (or shared memory for large datasets)
Content URIs: content://authority/path/id
- authority: unique identifier, usually package name
- path: data type (e.g., "notes", "users")
- id: specific record (optional)
When to use ContentProviders:
- Sharing data with other apps (contacts, media, files)
- Using SearchView suggestions
- Providing data to widgets (AppWidgetProvider)
- ContentProvider-based sync adapters
- FileProvider for secure file sharing between apps
Modern usage: While ContentProviders are fundamental Android components, modern apps often use Room DAO directly for internal data access and FileProvider for file sharing. ContentProviders remain essential for system integrations (Contacts, MediaStore, Calendar).
💻 Code Example
1// FileProvider — secure file sharing between apps2// AndroidManifest.xml:3// <provider4// android:name="androidx.core.content.FileProvider"5// android:authorities="${applicationId}.fileprovider"6// android:exported="false"7// android:grantUriPermissions="true">8// <meta-data9// android:name="android.support.FILE_PROVIDER_PATHS"10// android:resource="@xml/file_paths" />11// </provider>1213// Share a file securely14fun shareFile(context: Context, file: File) {15 val uri = FileProvider.getUriForFile(16 context,17 "${context.packageName}.fileprovider",18 file19 )20 val shareIntent = Intent(Intent.ACTION_SEND).apply {21 type = "application/pdf"22 putExtra(Intent.EXTRA_STREAM, uri)23 addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)24 }25 context.startActivity(Intent.createChooser(shareIntent, "Share via"))26}2728// Querying MediaStore (Android 10+ scoped storage)29suspend fun getImages(context: Context): List<MediaItem> {30 return withContext(Dispatchers.IO) {31 val images = mutableListOf<MediaItem>()32 val projection = arrayOf(33 MediaStore.Images.Media._ID,34 MediaStore.Images.Media.DISPLAY_NAME,35 MediaStore.Images.Media.SIZE36 )37 context.contentResolver.query(38 MediaStore.Images.Media.EXTERNAL_CONTENT_URI,39 projection, null, null,40 "${MediaStore.Images.Media.DATE_ADDED} DESC"41 )?.use { cursor ->42 val idCol = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)43 val nameCol = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)44 while (cursor.moveToNext()) {45 val id = cursor.getLong(idCol)46 val name = cursor.getString(nameCol)47 val uri = ContentUris.withAppendedId(48 MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id49 )50 images.add(MediaItem(id, name, uri))51 }52 }53 images54 }55}
🏋️ Practice Exercise
Practice:
- Implement a FileProvider and share an image with another app
- Query the MediaStore for all videos added in the last 7 days
- Explain Scoped Storage (Android 10+) — how does it change ContentProvider usage?
- When would you implement a custom ContentProvider vs using Room directly?
- Explain the difference between exported="true" and grantUriPermissions
⚠️ Common Mistakes
Exposing file:// URIs to other apps — causes FileUriExposedException on Android 7.0+, use FileProvider instead
Not closing Cursors — memory leak. Always use .use { } or try-with-resources
Querying ContentProviders on the main thread — can cause ANR, always use Dispatchers.IO
Not handling Scoped Storage changes (Android 10+) — legacy file access methods fail
💼 Interview Questions
🎤 Mock Interview
Mock interview is powered by AI for ContentProviders & Data Sharing. Login to unlock this feature.