Content Provider — je komponenta Androidu, která poskytuje jednotné rozhraní pro přístup k datům mezi aplikacemi. Abstrahuje fyzické úložiště (SQLite, soubory, síťové zdroje) a zajišťuje bezpečnou výměnu informací prostřednictvím ContentResolveru. Podle Android Developer Guide, 2026 je Content Provider jednou ze čtyř základních komponent aplikace pro Android vedle Activity, Service a BroadcastReceiver. Jeho úkolem je zpřístupnit data jiným aplikacím s kontrolou oprávnění pro čtení a zápis.
Hlavní body
Content Provider — je komponenta Androidu, která spravuje přístup k centralizovanému úložišti dat a poskytuje je jiným aplikacím prostřednictvím jednotného kontraktního rozhraní. Skrývá detaily implementace úložiště: data mohou být uložena v SQLite, v souborovém systému, v cloudu nebo být výsledkem síťového požadavku.
Android zahrnuje vestavěné Content Provider pro systémová data — ContactsContract, MediaStore, CalendarContract, CallLog. Aplikace třetích stran mohou také vytvářet vlastní poskytovatele pro bezpečnou výměnu dat. Každý poskytovatel je registrován v AndroidManifest.xml s uvedením authority — jedinečného řetězce, který tvoří první část URI.
Content Provider funguje podle modelu klient-server. Poskytovatel vystupuje jako server, který implementuje šest povinných metod: query, insert, update, delete, getType a onCreate. Klient (jiná aplikace) přistupuje k poskytovateli prostřednictvím ContentResolveru, který předává volání odpovídajícím metodám poskytovatele přes mechanismus IPC Androidu.
Každý Content Provider je identifikován URI schématu content://. Například content://com.example.app.provider/items. První část authority (com.example.app.provider) je vázána na třídu poskytovatele v manifestu. Cesta /items ukazuje na tabulku a /items/5 — na konkrétní záznam s ID=5.
Když aplikace zavolá ContentResolver.query(URI), Android zkontroluje oprávnění volajícího balíčku, najde poskytovatele podle authority a spustí jeho proces, pokud ještě není spuštěn. Poskytovatel provede dotaz a vrátí Cursor — objekt obsahující výsledek, který umožňuje klientovi iterovat přes záznamy.
Třída ContentProvider vyžaduje implementaci šesti abstraktních metod. Každá metoda přijímá URI a vrací výsledek odpovídající typu operace. Systém volá tyto metody z libovolného procesu, takže musí být thread-safe a nesmí blokovat provádění na dlouhou dobu.
Metoda query přijímá URI, pole sloupců projection, řetězec selection s argumenty a pořadí řazení. Vrací Cursor s daty. V implementaci je třeba rozebrat URI pomocí UriMatcher a provést odpovídající SQL dotaz do databáze.
Tyto metody mění data v úložišti. insert přijímá ContentValues — páry klíč-hodnota — a vrací URI nového záznamu. update a delete přijímají selection pro filtrování záznamů a vracejí počet ovlivněných řádků. Po změně dat musí poskytovatel oznámit tuto skutečnost prostřednictvím ContentResolver.notifyChange.
| Metoda | Účel | Návratová hodnota |
|---|---|---|
| query | Získání dat podle URI | Cursor nebo null |
| insert | Přidání nového záznamu | URI nového záznamu |
| update | Aktualizace existujících záznamů | int (počet řádků) |
| delete | Smazání záznamů | int (počet řádků) |
| getType | MIME typ pro URI | String |
| onCreate | Inicializace poskytovatele | boolean |
ContentResolver — je jednotný přístupový bod pro práci se všemi Content Provider v systému. Klientská aplikace nikdy nevolá metody poskytovatele přímo — pouze prostřednictvím ContentResolveru, který Android získává z kontextu. CRUD operace v ContentResolveru mají stejná jména jako u poskytovatele, ale přijímají URI místo přímých referencí.
Pro parsování příchozích URI uvnitř poskytovatele se používá UriMatcher. Umožňuje přiřadit URI k číselnému kódu — například URI content://authority/items dává kód 1 a content://authority/items/# — kód 2. Tím odpadá nutnost ručního parsování řetězce URI v každé metodě.
// Použití ContentResolver pro přístup ke kontaktům
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("Kontakty", "Jméno: $name")
}
}
Cursor je třeba po použití zavřít — v příkladu výše to dělá use (rozšiřující funkce Kotlinu). Pokud Cursor není uzavřen, dojde k úniku paměti, protože drží referenci na data v Binder poolu. Pro UI scénáře používejte CursorLoader nebo Room s LiveData/Flow.
Vytvoření vlastního Content Provider začíná děděním z třídy ContentProvider. Poskytovatel pracuje s databází SQLite prostřednictvím SQLiteOpenHelper a používá UriMatcher k určení typu dotazu. Podívejme se na minimální implementaci pro správu seznamu poznámek.
Poskytovatel se registruje v AndroidManifest.xml uvnitř tagu application. Atribut authorities nastavuje jedinečný identifikátor a exported určuje, zda jiné aplikace mohou k poskytovateli přistupovat. Bez exported=true je poskytovatel přístupný pouze v rámci vaší aplikace.
// Příklad Content Provider pro poznámky
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 vynechány pro stručnost
}
Po vytvoření třídy je třeba poskytovatele zaregistrovat v manifestu s atributy android:authorities a android:exported (true, pokud je poskytovatel veřejný). Systém vytváří instanci poskytovatele při prvním přístupu — to se děje ve vlákně UI, takže onCreate by se měl provádět rychle.
Content Provider umožňuje řídit přístup k datům na dvou úrovních: oprávnění pro čtení a oprávnění pro zápis. Ty se nastavují v manifestu atributy android:readPermission a android:writePermission. Pokud klientská aplikace nemá příslušné oprávnění, systém odmítne volání s výjimkou SecurityException.
Android podporuje dočasná oprávnění prostřednictvím příznaků FLAG_GRANT_READ_URI_PERMISSION a FLAG_GRANT_WRITE_URI_PERMISSION. To je užitečné, když aplikace předává URI souboru jiné aplikaci prostřednictvím Intent — příjemce získá přístup pouze ke konkrétnímu URI na omezenou dobu. Systém odvolá dočasné oprávnění po dokončení přijímající aplikace.
Pro systémové poskytovatele Android vyžaduje uvedení konkrétních oprávnění v manifestu aplikace. Například pro přístup ke kontaktům je potřeba READ_CONTACTS, pro kalendář — READ_CALENDAR. Od Androidu 6 jsou tato oprávnění vyžadována za běhu, nikoli při instalaci.
Často kladené otázky
Content Provider — je komponenta Androidu, která poskytuje standardní rozhraní pro výměnu dat mezi aplikacemi prostřednictvím ContentResolveru. Abstrahuje způsob ukládání (SQLite, soubory, síť) a zajišťuje bezpečný přístup k datům s kontrolou oprávnění pro čtení a zápis.
Authority — je jedinečný identifikační řetězec poskytovatele uvedený v AndroidManifest.xml. Tvoří první část URI content://authority/path a systém jej používá pro směrování volání ContentResolveru k příslušnému poskytovateli. Authority musí být jedinečná mezi všemi aplikacemi v zařízení.
UriMatcher přiřazuje URI k číselným kódům. Přidáte vzory pomocí addURI a poté zavoláte match pro získání kódu pro příchozí URI. To umožňuje v metodách query, insert, update, delete určit, která tabulka nebo záznam byl požadován, a provést odpovídající operaci s databází.
Ano, Cursor je třeba po použití zavřít. Pokud Cursor není uzavřen, dojde k úniku paměti, protože drží Binder referenci na data poskytovatele. V Kotlinu použijte funkci use pro automatické zavírání, v Javě — try-with-resources nebo volání cursor.close() v finally bloku.
Content Provider — je komponenta pro meziaplikační přístup k datům, zatímco SQLiteDatabase je interní úložiště jedné aplikace. Content Provider poskytuje URI rozhraní a kontrolu oprávnění, zatímco SQLiteDatabase pracuje přímo s databází bez bezpečnostních mechanismů na úrovni operačního systému.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také