Content Providers in Android
What Is a Content Provider?
A Content Provider acts as an interface for applications to access and modify data from other applications or databases securely. They use a uniform API, so developers don’t have to worry about the underlying data source. A Content Provider is accessed through a Content Resolver, which performs queries, updates, inserts, and deletes on the data.
Key Concepts in Content Providers
1. Getting Contacts Using Content Provider
Let's start by querying contacts using the ContactsContract content provider.
Example: Fetching Contact Names and Phone Numbers
To get contact details, you can use the ContactsContract content provider to access contacts stored on the device.
val contentResolver = context.contentResolver
val projection = arrayOf(
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER
)
val selection = "${ContactsContract.Contacts.HAS_PHONE_NUMBER} = 1"
val sortOrder = "${ContactsContract.Contacts.DISPLAY_NAME} ASC"
val cursor: Cursor? = contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
projection,
selection,
null,
sortOrder
)
cursor?.let {
while (it.moveToNext()) {
val name = it.getString(it.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
val phoneNumber = it.getString(it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
println("Name: $name, Phone Number: $phoneNumber")
}
it.close()
}
Explanation:
2. Getting Images and Sorting by Date
Next, let's retrieve images from the device’s media store and sort them by date (from last month).
Example: Fetching Images Sorted by Date
Next, let's retrieve images from the device’s media store and sort them by date (from last month).
val contentResolver = context.contentResolver
val projection = arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DATE_ADDED
)
val oneMonthAgo = System.currentTimeMillis() - (30L * 24 * 60 * 60 * 1000) // 30 days ago
val selection = "${MediaStore.Images.Media.DATE_ADDED} >= ?"
val selectionArgs = arrayOf(oneMonthAgo.toString())
val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC" // Sort by most recent
val cursor: Cursor? = contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
)
cursor?.let {
while (it.moveToNext()) {
val imageId = it.getLong(it.getColumnIndex(MediaStore.Images.Media._ID))
val dateAdded = it.getLong(it.getColumnIndex(MediaStore.Images.Media.DATE_ADDED))
println("Image ID: $imageId, Date Added: $dateAdded")
}
it.close()
}
Explanation:
领英推荐
3. Creating a Custom Content Provider for Room Database
Now, let’s create a custom content provider for a Room Database. This lets your app expose its data to other apps through a content provider.
Example: Creating a Content Provider for a Room Database
class NotesContentProvider : ContentProvider() {
private lateinit var notesDao: NotesDao
override fun onCreate(): Boolean {
val db = Room.databaseBuilder(context!!, AppDatabase::class.java, "notes.db").build()
notesDao = db.notesDao()
return true
}
override fun query(
uri: Uri,
projection: Array<String>?,
selection: String?,
selectionArgs: Array<String>?,
sortOrder: String?
): Cursor? {
val cursor = notesDao.getAllNotesCursor()
return cursor
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
val id = notesDao.insert(NoteEntity(values?.getAsString("title")!!, values.getAsString("content")!!))
return Uri.withAppendedPath(uri, id.toString())
}
override fun update(
uri: Uri,
values: ContentValues?,
selection: String?,
selectionArgs: Array<String>?
): Int {
val count = notesDao.updateNote(
values?.getAsLong("id")!!,
values.getAsString("title")!!,
values.getAsString("content")!!
)
return count
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
val count = notesDao.deleteNote(selectionArgs?.get(0)?.toLong() ?: -1)
return count
}
override fun getType(uri: Uri): String? {
return "vnd.android.cursor.dir/vnd.com.example.notes"
}
}
Explanation:
4. Creating a Custom Content Provider for SQLite Database
Finally, let’s create a custom content provider that interacts with a SQLite database.
Example: Content Provider for SQLite Database
class SQLiteNotesContentProvider : ContentProvider() {
private lateinit var dbHelper: SQLiteOpenHelper
override fun onCreate(): Boolean {
dbHelper = NotesDbHelper(context!!)
return true
}
override fun query(
uri: Uri,
projection: Array<String>?,
selection: String?,
selectionArgs: Array<String>?,
sortOrder: String?
): Cursor? {
return dbHelper.readableDatabase.query(
NotesContract.NotesEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
)
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
val id = dbHelper.writableDatabase.insert(NotesContract.NotesEntry.TABLE_NAME, null, values)
return Uri.withAppendedPath(uri, id.toString())
}
override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<String>?): Int {
return dbHelper.writableDatabase.update(
NotesContract.NotesEntry.TABLE_NAME,
values,
selection,
selectionArgs
)
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
return dbHelper.writableDatabase.delete(
NotesContract.NotesEntry.TABLE_NAME,
selection,
selectionArgs
)
}
override fun getType(uri: Uri): String? {
return "vnd.android.cursor.dir/vnd.com.example.notes"
}
}
Explanation:
Conclusion
In this article, we explored content providers in Kotlin for Android, covering how to use them to retrieve contacts and images, as well as how to create custom providers for both Room and SQLite databases. The key concepts of projection, selection, and sorting were explained with examples to help you understand how to manipulate data efficiently.
These providers are useful when you need to expose or share data between different apps, or if you want to allow access to data from different sources in your app.