Content Provider — је Android компонента која обезбеђује јединствени интерфејс за приступ подацима између апликација. Апстрахује физичко складиштење (SQLite, фајлови, мрежни извори) и обезбеђује сигурну размену информација путем ContentResolver-а. Према Android Developer Guide, 2026, Content Provider је једна од четири основне Android компоненте, уз Activity, Service и BroadcastReceiver. Његов задатак је да учини податке доступним другим апликацијама са контролом дозвола за читање и писање.
Главно
Content Provider — је Android компонента која управља приступом централизованом складишту података и обезбеђује их другим апликацијама кроз јединствени уговорни интерфејс. Сакрива детаље имплементације складиштења: подаци могу бити ускладиштени у SQLite, на фајл систему, у облаку или бити резултат мрежног захтева.
Android укључује уграђене Content Provider-е за системске податке — ContactsContract, MediaStore, CalendarContract, CallLog. Апликације трећих страна такође могу креирати сопствене провајдере за сигурну размену података. Сваки провајдер се региструје у AndroidManifest.xml са навођењем authority — јединственог низа који чини први део URI-ја.
Content Provider ради по моделу клијент-сервер. Провајдер делује као сервер који имплементира шест обавезних метода: query, insert, update, delete, getType и onCreate. Клијент (друга апликација) приступа провајдеру путем ContentResolver-а, који преусмерава позиве на одговарајуће методе провајдера кроз Android-ов IPC механизам.
Сваки Content Provider се идентификује URI схеме content://. На пример, content://com.example.app.provider/items. Први део authority (com.example.app.provider) се везује за класу провајдера у манифесту. Путања /items указује на табелу, а /items/5 — на одређени запис са ID=5.
Када апликација позове ContentResolver.query(URI), Android проверава дозволе пакета који позива, проналази провајдера по authority и покреће његов процес, ако већ није покренут. Провајдер извршава упит и враћа Cursor — објекат који садржи резултат и омогућава клијенту да итерира кроз записе.
Класа ContentProvider захтева имплементацију шест апстрактних метода. Свака метода прима URI и враћа резултат који одговара типу операције. Систем позива ове методе из било ког процеса, тако да оне морају бити thread-safe и не блокирати извршење на дуго време.
Метода query прима URI, низ колона projection, низ selection са аргументима и редослед сортирања. Враћа Cursor са подацима. У имплементацији потребно је раздвојити URI помоћу UriMatcher-а и извршити одговарајући SQL упит према бази података.
Ове методе мењају податке у складишту. insert прима ContentValues — парове кључ-вредност — и враћа URI новог записа. update и delete примају selection за филтрирање записа и враћају број погођених редова. Након измене података, провајдер мора обавестити о томе путем ContentResolver.notifyChange.
| Метода | Намена | Повратна вредност |
|---|---|---|
| query | Добијање података по URI-ју | Cursor или null |
| insert | Додавање новог записа | URI новог записа |
| update | Ажурирање постојећих записа | int (број редова) |
| delete | Брисање записа | int (број редова) |
| getType | MIME тип за URI | String |
| onCreate | Иницијализација провајдера | boolean |
ContentResolver — је јединствена тачка приступа за рад са свим Content Provider-има у систему. Клијентска апликација никада не позива методе провајдера директно — само путем ContentResolver-а, који Android добија из контекста. CRUD операције у ContentResolver-у имају иста имена као у провајдеру, али примају URI уместо директних референци.
За парсирање долазних URI-јева унутар провајдера користи се UriMatcher. Он омогућава повезивање URI-ја са нумеричким кодом — на пример, URI content://authority/items даје код 1, а content://authority/items/# — код 2. Ово елиминише потребу за ручним парсирањем низа URI-ја у свакој методи.
// Коришћење ContentResolver-а за приступ контактима
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("Контакти", "Име: $name")
}
}
Cursor након употребе обавезно треба затворити — у примеру изнад то ради use (Kotlin екстензиона функција). Ако Cursor није затворен, доћи ће до цурења меморије, јер држи референцу на податке у Binder-пулу. За UI сценарије користите CursorLoader или Room са LiveData/Flow.
Креирање сопственог Content Provider-а почиње наслеђивањем од класе ContentProvider. Провајдер ради са SQLite базом путем SQLiteOpenHelper-а и користи UriMatcher за одређивање типа упита. Размотримо минималну имплементацију за управљање списком белешки.
Провајдер се региструје у AndroidManifest.xml унутар application тага. Атрибут authorities поставља јединствени идентификатор, а exported одређује да ли друге апликације могу приступити провајдеру. Без exported=true провајдер је доступан само унутар ваше апликације.
// Пример Content Provider-а за белешке
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 изостављени ради краткоће
}
Након креирања класе, провајдер треба регистровати у манифесту са атрибутима android:authorities и android:exported (true ако је провајдер јаван). Систем креира инстанцу провајдера при првом приступу — то се дешава у UI нити, тако да onCreate треба да се изврши брзо.
Content Provider омогућава управљање приступом подацима на два нивоа: дозволе за читање и дозволе за писање. Оне се постављају у манифесту атрибутима android:readPermission и android:writePermission. Ако клијентска апликација нема одговарајућу дозволу, систем ће одбити позив са SecurityException.
Android подржава привремене дозволе кроз заставице FLAG_GRANT_READ_URI_PERMISSION и FLAG_GRANT_WRITE_URI_PERMISSION. Ово је корисно када апликација прослеђује URI фајла другој апликацији путем Intent-а — прималац добија приступ само одређеном URI-ју на ограничено време. Систем опозива привремену дозволу након завршетка апликације примаоца.
За системске провајдере, Android захтева навођење конкретних дозвола у манифесту апликације. На пример, за приступ контактима потребно је READ_CONTACTS, за календар — READ_CALENDAR. Почев од Android 6, ове дозволе се захтевају током извршавања, а не приликом инсталације.
Често постављана питања
Content Provider — је Android компонента која обезбеђује стандардни интерфејс за размену података између апликација путем ContentResolver-а. Апстрахује начин складиштења (SQLite, фајлови, мрежа) и обезбеђује сигуран приступ подацима са контролом дозвола за читање и писање.
Authority — је јединствени низ идентификатор провајдера који се наводи у AndroidManifest.xml. Он чини први део URI content://authority/path и користи се од стране система за усмеравање позива ContentResolver-а ка одговарајућем провајдеру. Authority мора бити јединствена међу свим апликацијама на уређају.
UriMatcher повезује URI-је са нумеричким кодовима. Додајете шаблоне путем addURI, а затим позивате match да бисте добили код за долазни URI. Ово омогућава у методама query, insert, update, delete да одредите која табела или запис је затражен и извршите одговарајућу операцију са базом података.
Да, Cursor обавезно треба затворити након употребе. Ако Cursor није затворен, доћи ће до цурења меморије, јер држи Binder референцу на податке провајдера. У Kotlin-у користите функцију use за аутоматско затварање, а у Java-и — try-with-resources или позив cursor.close() у finally блоку.
Content Provider — је компонента за међуапликацијски приступ подацима, док је SQLiteDatabase интерно складиште једне апликације. Content Provider пружа URI интерфејс и контролу дозвола, а SQLiteDatabase ради директно са базом без безбедносних механизама на нивоу оперативног система.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође