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:

  1. Client app calls ContentResolver.query(uri)
  2. ContentResolver sends request via Binder IPC to the ContentProvider's process
  3. ContentProvider processes the request and returns a Cursor
  4. 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

codeTap to expand ⛶
1// FileProvider — secure file sharing between apps
2// AndroidManifest.xml:
3// <provider
4// android:name="androidx.core.content.FileProvider"
5// android:authorities="${applicationId}.fileprovider"
6// android:exported="false"
7// android:grantUriPermissions="true">
8// <meta-data
9// android:name="android.support.FILE_PROVIDER_PATHS"
10// android:resource="@xml/file_paths" />
11// </provider>
12
13// Share a file securely
14fun shareFile(context: Context, file: File) {
15 val uri = FileProvider.getUriForFile(
16 context,
17 "${context.packageName}.fileprovider",
18 file
19 )
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}
27
28// 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.SIZE
36 )
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, id
49 )
50 images.add(MediaItem(id, name, uri))
51 }
52 }
53 images
54 }
55}

🏋️ Practice Exercise

Practice:

  1. Implement a FileProvider and share an image with another app
  2. Query the MediaStore for all videos added in the last 7 days
  3. Explain Scoped Storage (Android 10+) — how does it change ContentProvider usage?
  4. When would you implement a custom ContentProvider vs using Room directly?
  5. 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.