Content Providers in Android
A Content Provider is a component in Android used to manage access to a central repository of data. It allows applications to share data with each other in a structured and secure way. Content providers enable CRUD (Create, Read, Update, Delete) operations on app data.
Key Features of Content Providers
- Data Sharing: Allows sharing of data between different applications securely.
- Structured Access: Provides a standardized way to query and manipulate data using URIs.
- Integration: Works with ContentResolver for data access and manipulation.
Content Provider Components
- URI (Uniform Resource Identifier): A unique identifier for the data (e.g.,
content://com.example.provider/users
). - ContentResolver: Used by client applications to interact with the content provider.
- Cursor: A pointer to the result set of a query.
Creating a Content Provider
To create a custom content provider:
- Extend the
ContentProvider
class. - Implement its abstract methods:
onCreate()
: Initialize resources.query()
: Retrieve data.insert()
: Insert new data.update()
: Update existing data.delete()
: Delete data.getType()
: Return the MIME type of data.
Example: Custom Content Provider
1. ContentProvider Class
class MyContentProvider : ContentProvider() {
companion object {
const val AUTHORITY = "com.example.provider"
val CONTENT_URI: Uri = Uri.parse("content://$AUTHORITY/users")
const val TABLE_NAME = "users"
}
private lateinit var database: SQLiteDatabase
override fun onCreate(): Boolean {
val dbHelper = MyDatabaseHelper(context!!)
database = dbHelper.writableDatabase
return true
}
override fun query(
uri: Uri,
projection: Array<out String>?,
selection: String?,
selectionArgs: Array<out String>?,
sortOrder: String?
): Cursor? {
return database.query(TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder)
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
val id = database.insert(TABLE_NAME, null, values)
context?.contentResolver?.notifyChange(uri, null)
return ContentUris.withAppendedId(CONTENT_URI, id)
}
override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?): Int {
val rowsUpdated = database.update(TABLE_NAME, values, selection, selectionArgs)
context?.contentResolver?.notifyChange(uri, null)
return rowsUpdated
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
val rowsDeleted = database.delete(TABLE_NAME, selection, selectionArgs)
context?.contentResolver?.notifyChange(uri, null)
return rowsDeleted
}
override fun getType(uri: Uri): String? {
return "vnd.android.cursor.dir/$TABLE_NAME"
}
}
2. Database Helper
class MyDatabaseHelper(context: Context) : SQLiteOpenHelper(context, "MyDatabase", null, 1) {
override fun onCreate(db: SQLiteDatabase) {
db.execSQL("CREATE TABLE users (_id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL("DROP TABLE IF EXISTS users")
onCreate(db)
}
}
3. Manifest Declaration
Add the content provider in the AndroidManifest.xml
file.
<provider
android:name=".MyContentProvider"
android:authorities="com.example.provider"
android:exported="true"
android:grantUriPermissions="true" />
Using a Content Provider
1. Insert Data
val values = ContentValues().apply {
put("name", "John Doe")
put("email", "john.doe@example.com")
}
val uri = contentResolver.insert(MyContentProvider.CONTENT_URI, values)
Log.d("ContentProvider", "Inserted URI: $uri")
2. Query Data
val cursor = contentResolver.query(
MyContentProvider.CONTENT_URI,
arrayOf("_id", "name", "email"), // Columns
null, // Selection
null, // Selection Args
null // Sort Order
)
cursor?.use {
while (it.moveToNext()) {
val id = it.getInt(it.getColumnIndex("_id"))
val name = it.getString(it.getColumnIndex("name"))
val email = it.getString(it.getColumnIndex("email"))
Log.d("ContentProvider", "User: $id, $name, $email")
}
}
3. Update Data
val values = ContentValues().apply {
put("email", "new.email@example.com")
}
val rowsUpdated = contentResolver.update(
MyContentProvider.CONTENT_URI,
values,
"name = ?", // Selection
arrayOf("John Doe") // Selection Args
)
Log.d("ContentProvider", "Rows Updated: $rowsUpdated")
4. Delete Data
val rowsDeleted = contentResolver.delete(
MyContentProvider.CONTENT_URI,
"name = ?", // Selection
arrayOf("John Doe") // Selection Args
)
Log.d("ContentProvider", "Rows Deleted: $rowsDeleted")
Built-in Content Providers
Android includes several built-in content providers for common data types:
- Contacts:
ContactsContract
- Media Store:
MediaStore
- Settings:
Settings.System
Example: Querying contacts:
val cursor = contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
null, null, null, null
)
cursor?.use {
while (it.moveToNext()) {
val name = it.getString(it.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
Log.d("Contacts", "Name: $name")
}
}
Best Practices
- Secure Data Access: Use permissions or implement validation to prevent unauthorized access.
- Minimize Resource Usage: Optimize queries and limit the amount of data returned.
- Use URIs: Define consistent URI structures for easy data manipulation.