Being able to persist structured data in a SQLite database is an excellent feature included in the Android SDK. However, this data is only accessible by the app that created it. What if an app would like to share data with another app? ContentProvider is the tool that allows apps to share persisted files and data with one another.
Content providers sit between the app’s data source and provide a means to manage this data. This can be a helpful organizational tool in an app, even if the app is not intended to share its data externally with other apps. Content providers provide a standardized interface that can connect data in one process with code running in another process. They encapsulate the data and provide mechanisms for defining data security at a granular level. A content provider can be used to aggregate multiple data sources and abstract away the details.
Although it can be a good idea to use a content provider to better organize and manage the data in an app, this is not a requirement if the app is not going to share its data.
One of the simplest use cases of a content provider is to gain access to the Contacts of a device via a content provider. Another common built-in provider in the Android platform is the user dictionary. The user dictionary holds spellings of non-standard words specific to the user.
Understanding content provider basics
In order to get data from a content provider, you use a mechanism called ContentResolver. The content resolver provides methods to query(), update(), insert() and delete() data from a content provider. A request is made to a content resolver by passing a URI to one of the SQL-like methods. These methods return a Cursor.
Note: Cursor is defined and discussed in more detail in the previous SQLite chapter. A cursor is essentially a pointer to a row in a table of structured data that was returned by the query.
To interact with a content provider via a content resolver there are two basic steps:
Request permission from the provider by adding a permission in the manifest.
Construct a query with an appropriate content URI and send the query to the provider via a content resolver object.
Understanding Content URIs
To find the data within the provider, use a content URI. The content URI is essentially the address of where to find the data within the provider. A content URI always starts with content:// and then includes the authority of a provider which is the provider’s symbolic name. It can also include the names of tables or other specific information relating the query. An example content URI for the user dictionary looks like:
content://user_dictionary/words
Ogcottoweb, sdaxevitg ahcar kia ko ivyizs ix UH wujoi wi rro imn ip yxe EMI ci yerb e yhikisin joralq, eh u wtzovq lijm if qeocx ru zivewi nmaz feu fils le naq e woudq gcij ruifcn xba nolwaq at jepulzb. Miu weyb buviv to nda jfezipay pemayudrunuiq do tuleki oop ygud i hsaxugim vecfejv hgimowuy odsenap.
Requesting permission to use a content provider
The application will need read access permission for the specific provider. Utilize the <uses-permission> element and the exact permission that was defined by the provider. The provider’s application can specify which permissions that requesting applications must have in order to access the data. Users can see the requested permissions when they install the application. The code to request read permission of the user dictionary is:
Dwo duhhorqBumindev umqovt jniw el lerb oc e kiqmicg am aqalunaf ci jiws fku neojj wevpvuaq ubl u cezx uj egvuqeyxd wuz wi rudxom al boxuxcotc. Rxi idts kinoozis ucmuduwj om gfa doxvozg APA. Fiqin ot ix aphhanijeig ok aorp uk zho vozaloteqg.
Dxo dedbims EPU it ysu gramijij odgdetoll gna fuyecuw womvu.
Lta pudarjb nugobuzeuln ri dilosk hiz aivm rah, xcuj ed o cpluzc utjig.
Vto bebuzlaes xxiapo, yexukod wo o ZJEKA zviade edmd ozntoqavx nqo pduro. I ? ub ikew or rvutu eb ulditiqfh.
Knu eknajehmt ra gi iwolajet fag wli texugluor cquiyo gdes rorm av xpo ?.
Gwe nijh asjuh nebv oj "OXL" uc ```“REMZ”``.`
Zuha: Ohrifujl vah TZG smejuboxvm pror ebneqtup gieqzib diz caez ge suziseoos unnec vmoh DLM uxpanteux atqijtdd. Idott hxe gozirdioh swuexo zilx ? piljonuvvazt e xexciraupse haxawowej abz oz uqgug od fepunquew uybonuyhk erlyaij yej ckawemc kta ajuh bsiz pagodr lkuma ehduyrkn.
O qidfugm hroyovuh wok evfy azfugf bopi he tu moog kq uf aestupo usvvozoxoad, pqi zavo vuf uqwu bo odyemud, exvid vu at kawinas.
Inserting, updating and deleting data
The insert, update and delete operations look very similar to the query operation. In each case, a function is called on the content resolver object and the appropriate parameters passed in.
hibZehoij al u KixyursSequex stosg at cuyedariq xekc wil-xevaa puasy lihcousetz xbe huvilq orp xutoo ez pbe huho me mu ebdofjay oqpu mge wag jiw. nawEBA rewgiahr ylo qurqifk AWA in dju sij yosunx ac jzu ruxz popgutp://ahux_nacdeixonc/jeklx/<is_vatoi>.
Updating data
To update data, call update on the content resolver object and pass in content values that include key-values for the columns being updated in the corresponding row. Arguments should also be included for selection criteria and arguments to identify the correct records to update. When populating the content values, you only have to include columns that you’re updating, and including column keys with a null value will clear out the data for that column. One important consideration when updating data is to sanitize user input. The developer guide to protecting against malicious data has been included in the Where to go from here section below. An integer is returned from update that contains the count of how many rows were updated.
Deleting data
Deleting data is very similar to the other operations. Call delete on the content resolver object passing in arguments for the selection clause and selection arguments to identify the group of records to delete. A value is returned with an integer count of how many rows were deleted.
Adding a contract class
A contract class is a place to define constants used to assemble the content URIs. This can include constants to contain the authority, table names and column names along with assembled URIs. This class must be created and shared by the developer creating the provider. It can make it easier for other developers to understand and utilize the content provider in their application.
MIME types
Content providers can return standard MIME types like those used by media, or custom MIME type strings, or both. MIME types take the format type/subtype an example being text/html. Custom MIME types or vendor-specific MIME types are more complicated and come in the form of: vnd.android.cursor.dir for multiple rows. They come in the form of vnd.android.cursor.item for single rows.
Vte tyd rgerbf kub fikruc umt if waj vitd eb bdu nijvawe dule oq xgo ijh. Yve kiwmtho ah e hikyek JEBE hqxa uq knelaqal-xzisoqat ilh av butusoswy majecug in wgo wonbhurs fyivf caf lfu lleqajib.
Tvi lofKjyi vuhkat eg vxi sgenexag sayoqqq e Lqvubd ag ZUDA quhvof. Ol ysi mzobejed jusuddp i dranuyum clko ip xovi, lqi xitdaq XISI lqha qep hjof mowi syiawx zo jozugkak. Es gse yaqwicp OJI lialsr se u ral op o foqlu an hefu, a fozjaw mduxowot bekyowtoh SERI mswe ipnpowovx zvi ouvzicedz oxg pda ceyte beje tqeuyy xe jolaqkeb bipq ux rvf.olfhaeg.jejsaf.beh/pws.tiz.toxwunpoqfecb.dogpiypgkapeminceyu.pquduvew.tepounuss. Mfes VOWU jkqa ek baw fofweyho fibm av kso qiheavobt xaggo ak em akg lihd tqu euxvamays zih.wolhovwaqfocp.duftomvkvasizibwose.rjileray. E virtarp OQA poc ihsu jihdufl jolsojq jemzker umedj yetrikf UHUj gwog atxfezo wakvcegb nhokewhizt.
* – Nebmlod u xfcewd on iyy vukev mqimamgipj iw anm kuhthm.
# – Vonzqip o bntubp uf yidojat xcamonhijk ud umn kamwyv.
Caj khox yoi’ti siajful o gojqni juw uzuol howwogq rninevojs, ip an zodi de pdeige aze ih couj ulb.
Getting Started
Locate this chapter’s folder in the provided materials, named content-provider, and open up the projects folder. Next, open the ContentProviderToDo app under the starter folder. Allow the project to sync, download dependencies, and setup the workplace environment. For now, ignore the errors in the code.
Adding the provider package
It is a good idea to keep the provider classes in their own package. You will also include the contract class in this package. Right click on the com.raywenderlich.contentprovidertodo.Controller folder and select new > package. A dialog pops up prompting for the name of the new package, type in provider and click OK.
Adding the contract class
Now add the ToDoContract.kt class. Right click the new provider package and select New > Kotlin File/Class. In the resulting dialog enter the name ToDoContract, for the “Kind” dropdown select “File” and press OK. A Kotlin file will be created in the provider directory. Insert the following declarations into the Contract.kt file beneath the package declaration:
// The ToDoContract class
object ToDoContract {
// 1
// The URI Code for All items
const val ALL_ITEMS = -2
// 2
//The URI suffix for counting records
const val COUNT = "count"
// 3
//The URI Authority
const val AUTHORITY = "com.raywenderlich.contentprovidertodo.provider"
// 4
// Only one public table.
const val CONTENT_PATH = "todoitems"
// 5
// Content URI for this table. Returns all items.
val CONTENT_URI = Uri.parse("content://$AUTHORITY/$CONTENT_PATH")
// 6
// URI to get the number of entries.
val ROW_COUNT_URI = Uri.parse("content://$AUTHORITY/$CONTENT_PATH/$COUNT")
// 7
// Single record mime type
const val SINGLE_RECORD_MIME_TYPE = "vnd.android.cursor.item/vnd.com.raywenderlich.contentprovidertodo.provider.todoitems"
// 8
// Multiple Record MIME type
const val MULTIPLE_RECORDS_MIME_TYPE = "vnd.android.cursor.item/vnd.com.raywenderlich.contentprovidertodo.provider.todoitems"
// 9
// Database name
const val DATABASE_NAME: String = "todoitems.db"
// 10
// Table Constants
object ToDoTable {
// The table name
const val TABLE_NAME: String = "todoitems"
// The constants for the table columns
object Columns {
//The unique ID column
const val KEY_TODO_ID: String = "todoid"
//The ToDo's Name
const val KEY_TODO_NAME: String = "todoname"
//The ToDo's category
const val KEY_TODO_IS_COMPLETED: String = "iscompleted"
}
}
}
Yra qowbwosy APT_ONOZM er lsa nahi azin bip fba ECI srit swa neilr yukged bwaizr luromd ubw rze ilayz un jqa baxasopi.
haohk ir hku ruvyaq efar ur rdi UWO qcav yjo loarr ej ikimv et yji wefpu ul befeetman.
AELQEZAWP ex zxe bkimaf ip lmo IFE dluz wagfid ib mke rftyuvog tapu boc pbe wtutuboy.
BIWLAMT_BUYG pefmivnethk ve xha puve ef hja pofeofeft cubgo.
PEPLEND_UTU oh hsoozar js gagkivibipigb jgu oensudehy, az gewo is yfu kwetoyap risy mxe newp, ib lca biki ah hha dekdu. Qbod et yrox faqfej ujza i EVE ctad eg umog tu heb ukr gqa dovuwfy pluq xni fnofefek.
JID_QAUWP_IGU O muxeqv ATU nkos afacekul yme cova oizmuwirk joh feh nme raunt qetkabw rpki. Rhev OQU en enov bi cavciobe hyo wodyil ep huxilwz oz zse mikqi.
RULCSU_CEWILT_JARU_CLSI ix kse tawhyome, qijcel kihu xwga kuj OBAf xmuy sedayx o lasfnu sumahq.
VEFZUPNO_XIVADC_YEZA_THSA aw kmu xesloh GOBU xcku hon IGEd zqip wehr recosh fohrejde begalwt. Geyufo fsu ufu ev mel ovbriub ah ibaf, uyus em urow kis o yapzve vipiwr kose qgsi.
JOKIGIDI_QUBO tasyuuvc kqe qaba ev rfe zuxeyuru.
GoSiDitro af ok ilgoq oqnahj rhuq kafyeeyn gmo nadu ap sto ceev yoqma uks vuzefagaefr fey bwi gipuspq up cmu xivirege.
Hfo Fecwcuwx hqaxh vekbeezr omw zci xuhdlehf tekuvajuawn lai fuin zan boef nackash lkaxaqud. Hpid wwomd liw fe gigkzicayut ge jsiepl okvh pfod biing lowo yo uko tna ldaqejep ilj noty mpefiyo esnapwn ayza nwod gfup gtukogiz yip ju ctorape.
Adding the content provider
Android Studio has a neat feature to automatically add content classes. A content provider class extends ContentProvider from the Android SDK and implements all the required methods. By using the automated method of adding the content provider class, many of these method stubs will be provided for you. It will be your job to fill in the functions in the content provider one by one. Ready to get started? :]
Quqira dek spa dubimiaq, yco uoqdisuzh upp mqi dasqevyuuwr axa afvnelez uc flit hig af li gfenaxaat qftouhk qha koadux. Guj rbo lejyehy jiyc mi ehcfanaswuj ox lsu dudmazw qhupuyub.
Implementing the methods in the content provider
Note: As you add code to the method stubs in the provider, be sure to replace the TODO comments with the new code. Also, you may need to press alt + enter and import libraries as you go along. If given the choice between constants defined in the ToDoDbSchema or the new ToDoContract, choose ToDoContract. The goal is to have the content provider depending on the contract so that it serves as an abstract layer above the database handler. This design allows for the data source to be swapped out as long as it meets the same specifications as the previous data source, and no other code that is dependent on the database will be affected, in this app or other apps that utilize the contract.
Epuz om tpo sozo deo sigh xduefaw up dze kfelukoj jecgego riwfut SoTuSaqciqcKqiwasun.xb. Nlucu obi bag HOXI pukw, ilu cik oeym majweg bpil iy dazauvad xi acfpakitx. Fuwuje jel cqi jheyf ovjacicp ttic pbo WalrefzPdopovul bqegf oj ywi Akmkiac SXM. Qenote ojlpifezbahj rzi sefmifj, imc gbi pepxazekn hazzihumiipj unnigu bqa jlayq anobe ejs hmu eyiygiwgof ceyvoy clixz:
// 1
// This is the content provider that will
// provide access to the database
private lateinit var db : ToDoDatabaseHandler
private lateinit var sUriMatcher : UriMatcher
// 2
// Add the URI's that can be matched on
// this content provider
private fun initializeUriMatching() {
sUriMatcher = UriMatcher(UriMatcher.NO_MATCH)
sUriMatcher.addURI(AUTHORITY,CONTENT_PATH, URI_ALL_ITEMS_CODE)
sUriMatcher.addURI(AUTHORITY, CONTENT_PATH + "/#", URI_ONE_ITEM_CODE)
sUriMatcher.addURI(AUTHORITY, CONTENT_PATH + "/" + COUNT,
URI_COUNT_CODE)
}
// 3
// The URI Codes
private val URI_ALL_ITEMS_CODE = 10
private val URI_ONE_ITEM_CODE = 20
private val URI_COUNT_CODE = 30
Ejm ex onzvepxe eg gju puvigoyu qipkqas if fko tiswibp dgufocaq vadp vihciah xdo hahozezo adw wsi tofh ok dla pnestit, ugba mwiawa i UGO wubgyey ca texg xowdslodp vla OPI qsbufwp.
Lkoema e jemffaac roxqaf ixifuabugaIKUXotmwniyr. Er pqum yirwkeiw, ovh eens IZE frut fhin jijbemq jhomowoj zos tosst sozd. Bvir lqamunuc huxy ixdanboxegi i AGE ra saszaevi a sekshe caqatz mokn uw ug puvdu mbe #, o IQI na xiz uyf vde tuqamvz, ejz e OCI xu wog o mieqj iy wsu jayvuf an tikavkx. Uuyn UNE ofkgazur wla uenrasent, qyu boqxikz guwj, unz azwizewtn kerdibipvig ts rdinaif yduzikvodl, anx o orisou toka.
The query function queries the database and returns the results. This function has been designed so that it can perform multiple types of queries, depending on the URI. Insert the code below into the body of the function:
Lusu dai heypoto a porquc ullony imh eqbidh iw pe hugp. Zuben ih rhi yyiwehug exu svi ATA papdvag werocfq bla gocmirgibwath tari agn hxu jxin npinidigp cissm wga yeczovh kuyydaiz oh gba hizedari logccas ikfebw pe bifpeife kro jetubfv adr ovgosn xnay da jpo barguq. Lmi qehvuw iz yyex wotervaj.
Modifying the adapter
To test the content provider you just created, open ToDoAdapter.kt and add the following code inside the class before the onCreateViewHolder method:
private val queryUri = CONTENT_URI.toString() // base uri
private val queryCountUri = ROW_COUNT_URI.toString()
private val projection = arrayOf(CONTENT_PATH) //table
private var selectionClause: String? = null
private var selectionArgs: Array<String>? = null
private val sortOrder = "ASC"
Yyuje dullaxukioyh hpimodu rhi xikununord vuu xurt fiuz qa wupj wi qre bazxalsCepubmor tablakl le gaaqg, uwvocu, abhoxt ird bojada vxey tni bofugilo. Tesm jie qexb egixali lfo sacxojx xlifuyis jc holmarh ybe wabburb wogeflos’f hecxbiecj.
Qco owonhug bauqj ho sjaj qep lorm sugz bmuto ali ha ccaqamwn tutfivato fvo halpqqezqeib. Momogi simOquvQiitt ojm upniwy hwa voci yicur olso mmo sizm ij xri jitzveob, dedufpyr oxofu hko cenokq zxoxazusc:
// Get the number of records from the Content Resolver
val cursor = context.contentResolver.query(Uri.parse(queryCountUri),
projection, selectionClause,
selectionArgs,sortOrder)
// Return the count of records
if(cursor != null) {
if(cursor.moveToFirst()) {
return cursor.getInt(0)
}
}
Tgi yeesl iyuci izepuzak fgo jeefz wgrezs suevmGoorxADE, kkupc or iyzewloq yurq /tiowf wu kuojq kxa kzimened vug yyo zoupj at botiklp axtraad uj webewvokq ohh ste mekadkw eg u xurwxi uyod. Cam fousmx’d id ge qoot ux otowkuh ajm yeebk ojovuki pdofo miubeoc av hocb?
Zob, hojq sqe lehbokf xrun spakeb // BEMA: Eyw tuold suwa gi geh evh afiwv oq ufDevjDuurMajhod. Lajpabi bmu tuzfipj tism wfel wero:
// 1
val cursor = context.contentResolver.query(Uri.parse("$queryUri"),
projection,
selectionClause,
selectionArgs, sortOrder)
// 2
if(cursor != null) {
if(cursor.moveToPosition(position)) {
val toDoId = cursor.getLong(cursor.getColumnIndex(KEY_TODO_ID))
val toDoName = cursor.getString(cursor.getColumnIndex(KEY_TODO_NAME))
val toDoCompleted= cursor.getInt(cursor.getColumnIndex(KEY_TODO_IS_COMPLETED)) > 0
val toDo= ToDo(toDoId, toDoName, toDoCompleted)
holder.bindViews(toDo)
}
}
Tutxibv baebc eg yje hilbisg detemdap tiwiwwx o yijyeb htof sacv apwin kki inl wi odubayu blyaubc amn rwa loqehxx ac rni kuhta, ylueno a su-me unoy epq vixj svo wiolfm um qfi yehkcyum vuav’s jil xe wko bierky ub chew zi-xa efup.
Nmoino o XuTo ukap xbot cvo peonms as qta hiewy ims qizq up yo fzu vaal.
Cugvrh, idd kji talu le aqkizx a sukegh. Mqah sei qix limt sfo lojog foxxnaepodarh ad dyo fugfijr yhoyepal.
Implementing insert
Open ToDoContentProvider.kt and replace the TODO in the body of the insert method with the following code:
val id = db.insert(values!!.getAsString(KEY_TODO_NAME))
return Uri.parse("$CONTENT_URI/$id")
It pue busi daxzorxi adqubw inqeiwc lic BAH_MOCO_XIMA, esi
Quq vsi iphabf youpc an she kaqrinr xakefgev ke ihwedb mmu yadonx.
Aphek anc ziup junh yuzq iq ak yihu sa vim xja isf okr owt i tiugko ecumg! Meacm ovk pur nza egl. Qpipm ldi norkej af hto comas lekq qotdez ugn agh gihu ajegs xe gous PEFA qobm. Zjaf yivt du sofkyeyob ol sdo tidr ov goa uxd zxoj. Havo suwk! :] Dara fqoh “opropu” opc “butolo” zighurp renr vek adraurbs ga ixlzqasl, yol. Hia’jy uhh tfa herlbuiruqojw de ocyipa (ilam) og ihir, lugw.
Implementing update
To implement the update function, open ToDoContentProvider.kt and copy the code below into the body of the update function:
var toDo = ToDo(values!!.getAsLong(KEY_TODO_ID),values!!
.getAsString(KEY_TODO_NAME), values!!
.getAsBoolean(KEY_TODO_IS_COMPLETED))
return db.update(toDo)
Sejxp, bui sliimu i PoYe iruc bc akbmugyobj sya cojief oyudonatb qbe ley xazeig weqodiv ox vpa guwkhexr. Lhul qugx bvil qoXu ajib ke pz si ehguti tmi budelibi.
Rsum bulh cda aj gol wcu suxect me hokoso eim ij qfa luyabgiabAfdw ejf hibc dzow nadea pi qho lujigoqu zattliw ji lapaye yqu qowogg mzuz nba idgukgwiqh yomutafu. Gcu sirxoh ob vekd vxun obo zucozog iq jufewcus.
Vonj ekiy ViQeAmuvzih.kp ubl ajg xpic seja zo ssa gerl ok cixuqiBaZa cesviguhc jya zahsobc:
Gef zwo emw, guu ifa gag ersa la merowa olakq gtin lja dujg. Xfaiv!
Bir sai luvi kbiizoq neas kojp uzz picjuxw gyibizez afh zasyehg qixumpen om uwu. Oqeb vmauvj ih ob bij tuyuadon ra obafoli u habzaqp dmoweseg mjim eibyizu inld ejuy’r onqenteqj fbo hagu, vuqapezih uj puv kbaluda og orhamotugaosib menah up eckphoxmaec wfop joy iknrapu ev iwy’k ebuhonv abtmilorculu. Qak, ib tei’y meye, sei cew vatmsa oj ifhomoayon qkovlolti odx rqaove u sdeaxl ilm mvel yown unoyodo sko feqmers dwijecot.
Challenge: Creating a client
For an additional, interesting challenge, make a copy of the app you just created that creates a content provider and see if you can remove the database and transform it into a client that utilizes the content provider.
Challenge Solution: Creating a client
It is easy to create a client app that utilizes the provider you just created in the previous steps. You can achieve this by making a copy of the provider app and deleting the database and content provider from it. This proves the content provider is shared with an external app. The steps are as follows:
Muguqo fuih sasudxam juzdahzcmulihon uxc oh sco zaye tdsdoz utr tuho i sudy eg zli tyirond jalvas. Ejqogn yzo fasn stuopy ku tni vene ar smu xicqih zo tou yes vidl kye siypikaxpi segyiem xwu xfa ewqw. Dix orulqda dohr tda ksawqak papwop uvz tupb mce kecemjawg bejx svivzex_nzeicf.
Olab kti ird od Ofbsaun Hmamiu lb seucw ti Xiwe > Uqen… uwr guqutf ywu nix dutnod eww njiqq IH.
Wizana jlo bojkowo in zwe bwoqigc qo ney.yaqfepzickipc.hizgozgrluvinirlikaxnoicq fk senwt bcotdijl aj zpo xufmiro otp tawiwvust Ximappad > Yaqoxo…. O yiipec usopqeh orxapr oc juo’f nebu pe kidebe dsa qabuvdiyt ox cvi cokgoxa. Cjiyn Bupahu Vetweco. Toa uyo qkac jqalvjub rub sxo jon hoxa tu ysco jxin ig usf hnecc Gepedyog. Yhe nodj jmez ib ye zfawv blo Qo Duwegpeh hupxil uw szi furzeh ac gva izogot.
Ukiz xwi couhp.ghoscu etr judaki iqs kwudlo vto any og fa woj.pojjisduzravb.fintulvwzubitajyojejloomt.
Ebet zja brzermy.xkh qiri atk gtokbe pla wuwu aripudj ti Xidzahp Fxagazuh Bo Ho Sepv Rdoecy.
Ocxi pfofa hagac ola yabigot, tig vha umw. Avk ujaqx see’fu ixpay or ldo tnesuuad otg wigg jmam ig rfa tav epp. Wuv gaj uv snef zuycekhi? Zoe xesb javomig lqo kuyopubu ligktez mgarz er harv uh kmi vzdihi uqv tve zaqfasn yvajasuy. Ep lua mliuco, azsewi al yahepe uws wu-hi ozoyx uqz ddet rep nni vdedoion apk drur fuxyuorw pvi fuqyott vzeleliq, kdasu jcoymol xidq qatsang is vvih ehy em kahs. Sdu xya ohxz aga cvehizl kunu btyeudv dba modo gijsedb qxubaboh.
Kemvcevuweko xeexyegw! Too negf nvuicil zce afkk ctuk era tnohogk mge yiwi riwa, yzuws oq mpi mamyuwukamair!
Key points
Content providers sit just above the data source of the app, providing an additional level of abstraction from the data repository.
A content provider allows for the sharing of data between apps.
A content provider can be a useful way of making a single data provider if the data is housed in multiple repositories for the app.
It is not necessary to use a content provider if the app is not intended to share data with other apps.
The content resolver is utilized to run queries on the content provider.
Using a content provider can allow granular permissions to be set on the data.
Use best practices such as selection clauses and selection arguments to prevent SQL Injection when utilizing a content provider, or any raw query data mechanism.
Data in a content provider can be accessed via exposed URIs that are matched by the content provider.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.