Content Provider — is een Android-component die een uniforme interface biedt voor toegang tot gegevens tussen applicaties. Het abstraheert fysieke opslag (SQLite, bestanden, netwerkbronnen) en zorgt voor veilige gegevensuitwisseling via ContentResolver. Volgens Android Developer Guide, 2026 is Content Provider een van de vier basiscomponenten van een Android-applicatie, naast Activity, Service en BroadcastReceiver. Zijn taak is om gegevens beschikbaar te maken voor andere applicaties met controle over lees- en schrijfrechten.
Belangrijkste punten
Content Provider — is een Android-component die toegang beheert tot een gecentraliseerde gegevensopslag en deze aan andere applicaties aanbiedt via een uniforme contractinterface. Het verbergt de implementatiedetails van de opslag: gegevens kunnen worden opgeslagen in SQLite, op het bestandssysteem, in de cloud of het resultaat zijn van een netwerkverzoek.
Android bevat ingebouwde Content Providers voor systeemgegevens — ContactsContract, MediaStore, CalendarContract, CallLog. Applicaties van derden kunnen ook eigen providers maken voor veilige gegevensuitwisseling. Elke provider wordt geregistreerd in AndroidManifest.xml met vermelding van authority — een unieke tekenreeks die het eerste deel van de URI vormt.
Content Provider werkt volgens het client-server-model. De provider fungeert als server die zes verplichte methoden implementeert: query, insert, update, delete, getType en onCreate. De client (een andere applicatie) benadert de provider via ContentResolver, die aanroepen doorstuurt naar de overeenkomstige methoden van de provider via het Android IPC-mechanisme.
Elke Content Provider wordt geïdentificeerd door een URI van het schema content://. Bijvoorbeeld content://com.example.app.provider/items. Het eerste deel authority (com.example.app.provider) wordt in het manifest aan de providerklasse gekoppeld. Het pad /items verwijst naar een tabel, en /items/5 naar een specifiek record met ID=5.
Wanneer een applicatie ContentResolver.query(URI) aanroept, controleert Android de machtigingen van het aanroepende pakket, vindt de provider via authority en start het proces indien het nog niet actief is. De provider voert de query uit en retourneert een Cursor — een object dat het resultaat bevat en de client in staat stelt door records te itereren.
De klasse ContentProvider vereist de implementatie van zes abstracte methoden. Elke methode ontvangt een URI en retourneert een resultaat dat overeenkomt met het bewerkingstype. Het systeem roept deze methoden vanuit elk proces aan, dus ze moeten thread-safe zijn en de uitvoering niet langdurig blokkeren.
De methode query ontvangt een URI, een array van kolommen (projection), een selection-tekenreeks met argumenten en een sorteerorde. Het retourneert een Cursor met gegevens. In de implementatie moet de URI worden geparseerd met UriMatcher en de bijbehorende SQL-query op de database worden uitgevoerd.
Deze methoden wijzigen gegevens in de opslag. insert ontvangt ContentValues — sleutel-waardeparen — en retourneert de URI van het nieuwe record. update en delete ontvangen selection voor het filteren van records en retourneren het aantal beïnvloede rijen. Na het wijzigen van gegevens moet de provider hiervan op de hoogte stellen via ContentResolver.notifyChange.
| Methode | Doel | Retourneert |
|---|---|---|
| query | Gegevens ophalen via URI | Cursor of null |
| insert | Nieuw record toevoegen | URI van nieuw record |
| update | Bestaande records bijwerken | int (aantal rijen) |
| delete | Records verwijderen | int (aantal rijen) |
| getType | MIME-type voor URI | String |
| onCreate | Provider initialiseren | boolean |
ContentResolver — is een uniform toegangspunt voor het werken met alle Content Providers in het systeem. De client-applicatie roept nooit direct methoden van de provider aan — alleen via ContentResolver, die Android uit de context haalt. CRUD-bewerkingen in ContentResolver hebben dezelfde namen als bij de provider, maar accepteren URI in plaats van directe verwijzingen.
Voor het parsen van inkomende URI's binnen de provider wordt UriMatcher gebruikt. Het maakt het mogelijk om een URI aan een numerieke code te koppelen — bijvoorbeeld URI content://authority/items geeft code 1, en content://authority/items/# — code 2. Dit elimineert de noodzaak voor handmatig parsen van de URI-tekenreeks in elke methode.
// ContentResolver gebruiken om contactpersonen te benaderen
val uri = ContactsContract.Contacts.CONTENT_URI
val cursor = contentResolver.query(
uri,
arrayOf(ContactsContract.Contacts.DISPLAY_NAME),
null, null, null
)
cursor?.use {
while (it.moveToNext()) {
val name = it.getString(it.getColumnIndexOrThrow(
ContactsContract.Contacts.DISPLAY_NAME
))
Log.d("Contactpersonen", "Naam: $name")
}
}
Cursor moet na gebruik worden gesloten — in bovenstaand voorbeeld doet use (de Kotlin-extensiefunctie) dit. Als Cursor niet wordt gesloten, treedt er een geheugenlek op omdat het een verwijzing naar gegevens in de Binder-pool vasthoudt. Gebruik voor UI-scenario's CursorLoader of Room met LiveData/Flow.
Het maken van een eigen Content Provider begint met overerven van de klasse ContentProvider. De provider werkt met een SQLite-database via SQLiteOpenHelper en gebruikt UriMatcher om het querytype te bepalen. Laten we een minimale implementatie bekijken voor het beheren van een notitielijst.
De provider wordt geregistreerd in AndroidManifest.xml binnen de application-tag. Het attribuut authorities stelt een unieke identificatie in, en exported bepaalt of andere applicaties toegang hebben tot de provider. Zonder exported=true is de provider alleen binnen uw eigen applicatie toegankelijk.
// Voorbeeld Content Provider voor notities
class NotesProvider : ContentProvider() {
companion object {
const val AUTHORITY = "com.example.app.notes"
const val NOTES_PATH = "notes"
const val NOTES_URI = "content://$AUTHORITY/$NOTES_PATH"
const val NOTES_ID = "content://$AUTHORITY/$NOTES_PATH/#"
private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
addURI(AUTHORITY, NOTES_PATH, 1)
addURI(AUTHORITY, "$NOTES_PATH/#", 2)
}
}
override fun query(uri: Uri, projection: Array<String>?,
selection: String?, args: Array<String>?, sort: String?): Cursor? {
return when (uriMatcher.match(uri)) {
1 -> dbHelper.readableDatabase.query(TABLE_NOTES,
projection, selection, args, null, null, sort)
2 -> dbHelper.readableDatabase.query(TABLE_NOTES,
projection, "_id=?", arrayOf(uri.lastPathSegment), null, null, null)
else -> throw IllegalArgumentException("Unknown URI: $uri")
}
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
val id = dbHelper.writableDatabase.insert(TABLE_NOTES, null, values)
context?.contentResolver?.notifyChange(uri, null)
return ContentUris.withAppendedId(uri, id)
}
override fun delete(uri: Uri, selection: String?, args: Array<String>?): Int {
val count = dbHelper.writableDatabase.delete(TABLE_NOTES, selection, args)
context?.contentResolver?.notifyChange(uri, null)
return count
}
// getType, update, onCreate weggelaten voor beknoptheid
}
Na het maken van de klasse moet de provider worden geregistreerd in het manifest met de attributen android:authorities en android:exported (true als de provider openbaar is). Het systeem maakt een instantie van de provider bij de eerste toegang — dit gebeurt in de UI-thread, dus onCreate moet snel worden uitgevoerd.
Content Provider maakt het mogelijk de toegang tot gegevens op twee niveaus te beheren: leesmachtigingen en schrijfmachtigingen. Deze worden in het manifest ingesteld met de attributen android:readPermission en android:writePermission. Als de client-applicatie niet over de juiste machtiging beschikt, wijst het systeem de aanroep af met SecurityException.
Android ondersteunt tijdelijke machtigingen via de vlaggen FLAG_GRANT_READ_URI_PERMISSION en FLAG_GRANT_WRITE_URI_PERMISSION. Dit is handig wanneer een applicatie de URI van een bestand naar een andere applicatie stuurt via Intent — de ontvanger krijgt alleen toegang tot de specifieke URI voor een beperkte tijd. Het systeem trekt de tijdelijke machtiging in nadat de ontvangende applicatie is voltooid.
Voor systeemproviders vereist Android het specificeren van concrete machtigingen in het applicatiemanifest. Bijvoorbeeld voor toegang tot contacten is READ_CONTACTS nodig, voor de agenda — READ_CALENDAR. Vanaf Android 6 worden deze machtigingen tijdens de uitvoering gevraagd, niet bij installatie.
Veelgestelde vragen
Content Provider — is een Android-component die een standaardinterface biedt voor gegevensuitwisseling tussen applicaties via ContentResolver. Het abstraheert de opslagmethode (SQLite, bestanden, netwerk) en zorgt voor veilige toegang tot gegevens met controle over lees- en schrijfmachtigingen.
Authority — is een unieke identificatietekenreeks van de provider die wordt opgegeven in AndroidManifest.xml. Het vormt het eerste deel van de URI content://authority/path en wordt door het systeem gebruikt voor het routeren van ContentResolver-aanroepen naar de juiste provider. Authority moet uniek zijn onder alle applicaties op het apparaat.
UriMatcher koppelt URI's aan numerieke codes. U voegt patronen toe via addURI en roept vervolgens match aan om de code voor een inkomende URI te krijgen. Dit maakt het mogelijk in de methoden query, insert, update, delete te bepalen welke tabel of record is opgevraagd en de bijbehorende bewerking op de database uit te voeren.
Ja, Cursor moet na gebruik worden gesloten. Als Cursor niet wordt gesloten, treedt er een geheugenlek op omdat het een Binder-verwijzing naar de providergegevens vasthoudt. Gebruik in Kotlin de functie use voor automatisch sluiten, en in Java — try-with-resources of cursor.close() in een finally-blok.
Content Provider — is een component voor gegevenstoegang tussen applicaties, terwijl SQLiteDatabase een interne opslag van één applicatie is. Content Provider biedt een URI-interface en machtigingscontrole, terwijl SQLiteDatabase rechtstreeks met de database werkt zonder beveiligingsmechanismen op OS-niveau.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook