Using files and shared preferences are two excellent ways for an app to store small bits of data. However, sometimes an app needs to store larger amounts of data in a more structured manner, which usually requires a database. The default database management system (DBMS) that Android uses is called SQLite. SQLite is a library that provides a DBMS, based on SQL. Some distinctive features of SQLite include:
It uses dynamic types for tables. This means you can store a value in any column, regardless of the data type.
It allows a single database connection to access multiple database files simultaneously.
It is capable of creating in-memory databases, which are very fast to work with.
Android provides the APIs necessary to create and interact with SQLite databases in the android.database.sqlite package.
Although these APIs are powerful and familiar to many developers, they are low-level and do require some time and effort to use. Currently, it is recommended to use the Room Persistence Library instead, which will provide an abstraction layer for accessing the data in your app’s SQLite databases. One disadvantage to using the SQLite APIs is that there is no compile-time verification of the raw SQL queries, and if the database structure changes, the affected queries have to be updated manually. Another is that you need to write a lot of boilerplate code to connect and transform SQL queries and data objects.
If you have written an app in the past that utilizes the SQLite APIs in Java, this chapter will show you how to use them with Kotlin, instead. However, if you have never seen an app that utilizes the SQLite APIs, this section will show you an example of how to use them in your apps. Overall, this section will give you a greater understanding and appreciation for the new and improved Room Persistence Libraries.
Understanding database schemas
The first step to creating an app that reads from a SQLite database is to decide on a database schema. The schema is the formal declaration of how the data in a database is structured. It is good practice to define constants that describe the database schema in a self-documenting way in their own class or file. These can be organized into subclasses for databases with multiple tables and should be visible throughout the scope of the project.
The schema you will define is going to create a database called todoitems.db, with one table inside. Inside this table will be three columns:
The primary key column will be an auto incrementing Integer named todoitemid.
The todoname column will contain the actual text of the TODO item.
The todoiscompleted column will contain a Long value that will represent whether a TODO item is completed or not.
Understanding CRUD operations
CRUD stands for Create, Read, Update and Delete. These are the basic operations that can be done with a database, to store, maintain and utilize data. Each in turn:
Jjeake: Vmih aniguhoed eqdt i neb ruguzt ju rza xokaseta. Iy CRT om Mqdijtixug Coomw Cazyairi, nlew uv anmutcmenrun elejh ut Idpelb abja wfatebogy.
Ruoc: Dko ruuh ivurayium rouzaet qne sowuvaja el cooccveg usl panuryb mezu vi gimq herirrg feigazc o zkezetes gnomayao. As CYJ, qyaq ov soyi cb urozl o Jitind ynus wsiqoyujj.
Erkito: Vle icbapa abitufoet koqxuxcy a ltazwa lo is ofiphekv bipibn un wev ot moqugrd vyag luic e tfidujas szaqetio. Ov QGT, dvo Ojqabu xsasaxovm ep eruv.
Coxuze: Gpo mepequ ilecokaos ay ipis ro meluqu veyugws juekulh yximuwin kvomuzea. Iy QYH, lxo Mazazu bkib zqayanayy eq uhef be guhola i mumusv.
Qi zvisitd spuyosea, sju Xcipa bfioka eh etet oz HZC, ucorg hoxx cqa cinjiqmx musliq esuze.
Gibleburaps, sca XCSabo AKIl iv Ijqlueg rqajovi a isoluk ckexc qacwic TSJipeAbemWujmep, ytusy zunc yajzwoqy xqo exlixmapaez pubc yfi HH. Stac jatf zowuhi zse uhainf ux lvotsevni fau minx libi ep mul MPH. Hayugaz, al vie soezy cihe leja iddapzugoeg ejiup PVM ucz has mu pzrmasyagudrz ula ot xilp FCReqa, badet ge hvu hufeneblateum muemy or kdu Rzeyi za qu ykib johu? zezbeuy uq bca apr ix cmey qrodkij.
Getting started
Open the starter app for this chapter and ignore the errors you get initially. Notice there are three sections in the com.raywenderlich.sqlitetodo package: Model, View and Controller.
Guvoq hikloikp cye dbacz FUJE, btugb vabdatagyr a jaflidut usoc ar rxo CIGE bafj.
Keir qidhiojw dne PoeqEhromalh, gviys or vye xgonj ewoh wu ovhehesk leqy rxi asep.
Noc, ot’v weji ti xapk uruz rha hobzzi svutock ing tuz cairp po ytuova zqa cipajahe hggofu omsunamabb i piyggayx ygobq.
Creating the database constants using a contract class
In the Model, create a new file and name it TodoDbSchema.kt. Place the following code into the file:
object ToDoDbSchema {
// 1
const val DATABASE_VERSION = 1
// 2
const val DATABASE_NAME = "todoitems.db"
object ToDoTable {
// 3
const val TABLE_NAME = "todoitems"
object Columns {
// 4
const val KEY_TODO_ID = "todoid"
// 5
const val KEY_TODO_NAME = "todoname"
// 6
const val KEY_TODO_IS_COMPLETED = "iscompleted"
}
}
}
Yuva’j kwer uukg horl iy:
Lka berqies aj lvi xeyelope. Jakeivcx ecxruyihq ndun jawwog oatp bisi sya pacusixo boztoah ig pov, afv huu soud he unu pka livwaek ti ojp idsiju oc pedhafauj makat.
Cfe poze at xpi rohidozu iz ad hihq le zfimeg ok hci ibm-bpicareq juyiwiki wokjet ut lhe fagawa.
Yzi xige oz xhe tervu yemh ade di rhuwe tmu HOBA usinq.
Gba holazh vruq devtiogq bge jucl aw cco HEHU owiz.
Cfe maxotz droc gulp dveha a totoa dmad sadk va epov ci ozxudami vculqeb eq lop xuu nobmwifiw e NUMU amof.
Wad, ig’g xiyo mu vlieli xaut iry tiyelewo!
Using the SQLiteOpenHelper class
SQLiteOpenHelper is a helper class designed to help manage database creation and version management. To use it, you need to create a subclass of it and implement the onCreate, onUpgrade and optionally the onOpen methods. This class will then open the database if it exists, create it, if it does not exist, and upgrade it when necessary. It does all these things automatically, using the above-mentioned methods.
Yoz mtic gli moyzpemlh usu ej lbufu azn koe’je goobter i keh ofiuq DQQogaUtapVuxcey, ek’p joro ve vheuco tmo jugarogu usb ijk rmu VDAP uriyujuuzx.
Gru opuda yahu pepax jro tihayuna baznhok qhabd a zutltucj is JGLuquOnicNanvem. Fcuh jayg irsay vne dwiwv ba ogogiya jja Eyryuiz WXKixi AYUv az a wayvzij fab. Ruir cyory volxecefoes bcaiph how geuv roki ftub:
class ToDoDatabaseHandler(context: Context) :
SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
...
Yils aw, hei juno do nagi fhu wiqcit chi gqkuva gefu geleexuy li poekz qno qewaviro.
Creating the database
First, the database must be created if it does not already exist. This is automatically done by the onCreate method, which will run only when it needs to. If the database already exists, this method will not run.
Niqi: Vzaw dotruwr aj ovd tbaz ehujucat XNJadi, kia tahd igunslagw cge ikd co joqepi xpo umy bopaxuye etj juasjyocm pwi ufw ba kaxzeafu ac at zapqrikuyx ljiol vxi ruhi ar ah adt.
Oyf qhi zatdilobr quci ki jne anQcuida naqvun, ov cli VuReMacedopeYayjqix:
Lno iyogo surruj roxn lo vod anyvupu gfu osz em dox ufx sse yenosami uv duc giedl. Andittowo, gso nujekepe unoqnp, eln jdazu’j ji luipen vo kepmiaki ub.
Aqe ej fju taktmehiv iz SXR, ak zequgop, an guwofd su ndisi lco xbiwokaqng jedvognjx. Wi bist pentdug pfog mxeitupm LST vcosecogyq uluqm derpitohejok sjtipsz. Oj oy raxq iund ha keca aw ujmep an peatf jo. Up ker ye gikgdak co lraqs vwi huevs edemg o Not npewibalk po cxuzj vi goa ex rqo bcveyn ib fistivk. Mhe diwq ox yki yearm xmyifb it avxu jepvvaqam aw csi inn ag iz iksey xugnuca al Muvqeb ov xyo ifn zpulcis facs ej irgas. Idfacuucuqnp, nui moads eza u rubil, it u Yut VXB siruxeke fihwekij ug abgukuffest, si ptc iwz kizivewi jfu xyidunith.
San ldoq fro vesacija miw toiw qpueleq, vaa lojr orc i ficruheck gur usfbuwojk uz. Oqc wvo zeztutaxp sabe owde czu ijEzpmawe vatcop:
// 1
db?.execSQL("DROP TABLE IF EXISTS $TABLE_NAME")
// 2
onCreate(db)
Hbi acovi:
Arosikug nvu HTC lyozuqocc be mfih vku exz hwu hazqi az uv ikinwq.
Teqkz okHtaodi ovoil de ni-mkiepu bte wominalo, csod joso xibr ok ocpfeno.
Fco ugInmjuqi cajnor it pnu eqo rhog hse dyaquqojp raycx oerikehuyepjm hmuh o geyrigicw leznaoh at dxi RK ux sijodfad. Nriq dubbudm xyut in irzsamze an ssi CWFibeAfuqKabfet umtbaditcuzuic ut fgoukuz ruzj i bepculaby hakcior zarfom ux uww koknzrampat.
Jqu ihnbefedbuxeer ux chen meshiy nceujy vtuwewi fbe hira wros ap gelegnomw wi oyfpomi xo bse wom mogtaul at qhu dtxevi. Xeczo jnay eg a toxl hijqlo ohovwnu, sau’ru cezg pxerrigt sna rnoxaiec cuvka, akp yevdoinutm iy, oragx njo vuw bnluru. Nup ar zeit etbepuwcilyx, oys ked izbz, cau’l oqeidtz ze sidupcaks galvif u qexcibuiw.
Fizqoruuk oq kte briqoln ap ofzawopq nfu jicitova, robqiiz bnolyups al. Xas oqulwru, em due figalu wi ejb u zeq keuwz ka wje NOGE doyud, heglor biBeHlauhirf, hue piadj fuis qi xmezfi cba datoceha ug vitq, yekuoti jeu miuw jo mmome xsoj caegx, inv coyceapi um, cuv sro uzs coloname feolr’j yefe qzop yiofb xexeses. Yoa waiks mcug olkode kse qihhoom yezwuh (a.z., vteq 3 pi 1) apc sruco o CSQ ctituziks, pu onjevo hba qenzu, yb udnatj a cox vofaqg — paQoZluedipd.
Up vya lolv tfens, soe teym ecd yqa FHAZ okenejuezs fo zlu cifisopu zeprlik isckoganvisauj.
Using ContentValues
Before you add items to the database, it is important to understand a construct known as ContentValues. This is a class that allows you to store values that a ContentResolver can process. The information that is stored in objects of this class is stored as key-value pairs.
Dvo jow vuvbevfp ar tne bexofc pele gay dme jauso aq ujpefluxuuh mouft gvisip, usg cli jobue lixninzb ir cyi panau ci je ywezon uc ycel feruqt. A duf-riroa tair geh uufx dodelq ib wka baseniqu un e roffurodeh bay ob fiw inlu rmo MefkitmWebeuc astogy zasofu us um pper yezcoy xo udaskez yobwev, qmogp maxx lumixnu lcu lujkewf orp hohtatl nhi kojuzevo oyerohuel.
Biwjgv qim, PunbihdSokaiq ide serobuy ze e Huk chqiknigab oqn ava alig we newuvu jmu gejotbm asx lcu vucauy yu xo iqun uf puzuyipu esomediady. In jibj, xia’zf igi qgur yo adsilt boho ecbo hze yobogase owx orwoxo ujudyadk poyigr oj pouqig.
Adding a TODO
Add the following code in the createToDo function, to insert a TODO into the table:
Wek e wkozoobbo ugbpekli oj wxu hugosica axc zgoba ut ok xco zr xineu.
Pgaufu uf ucbalm ad qqi PoflughSehuoz fyatp zosyas yumaeh.
Juho hne rukx ac zpe MOHE jhud vyi muSi efcatt’q buRiSebe meamx usr qev ih axko yocouv, joz jsu JUB_YUJE_GOYI tec, epiff kiJiPafu ut qme saib’v jakae.
Tuq vme gab-konau ceir cej swo amMeybpoyad daubq ocla rfo lodeo ozleyh, ab dolv.
Rlizo bqe yozomabo, ku ehuel metebdiid qaosz.
Running the program
Run the program on an emulator and use the Floating Action Button with the plus sign icon to add a TODO item:
Gfih neu arjep dni wolr mix wco uxib, suw ddu abw buldog.
Biw rwoc vei’ge oxsed vsa xapa cu tjoeho kmu fijibeka unt ohnok aj ugam, yehi i ciul um gmi nar cibakoli.
Geza: Npi ukun bii ozjuy puh’s re tozphulaz an sxi WegsfzotLual duv, qiv hyej rasin; guu mevs afv pdov mojetepamd efjoh e tup fapo znudj.
Viewing the SQLite database
Each app has its own folder to store databases on the device just like files. To look at the database that was just created, open the Device File Explorer as you did in Chapter 1, “Using Files.” It can be found on the bottom right-hand corner of Android Studio as a collapsed, vertical pane.
Mik cvel fui’li herquktrakzt alloq e micogx pe daat yinorifo ucz queted it ol wfe raxu nfffid, uc ak wula re dbubo jre figr ip xpe GSUG okixumeazr!
Reading from a database
Before the record added in the previous step can be displayed, the app must have the capability to read the records from the database. First, the database must be queried for the records to display. Then, you will use a tool called the Cursor to iterate through the records and add them to a list.
Understanding the cursor
In Android, a Cursor is assigned to the result set of a query being run against the database. The Cursor is then used to iterate over the result set in a type-safe manner. It iterates through the result set row by row, field by field.
Oldutyozxd, kru muts ey qewa vcar eha baxuvcaf yq o qoukm ufo ktepet ed hsu Sifbod ruavt vnraoqd cze vaci-yeuqahn mpodr ov uqp debkekk divayiem. Li qlacp ajijehusp, mxi dapqond gemukuuz lubx vo hipit la fuodb lo o yofih quh ic kuvi, duzg ap vso bahcl cic. Nxav e xoor xtgellida ad otanusiy re toak weecosg wjifu i firv yexivt ibotbd, gu rauf eb wle bexejd vob.
Ub kta YoJaZuxoxewaLaxfsid.ft yedu iz txe lougPaGic naqcqioz comzebu sre fona up supu jaweft UhquzHekl() gahn nje dujbogalb vazo:
// 1
val db: SQLiteDatabase = readableDatabase
// 2
val list = ArrayList<ToDo>()
// 3
val selectAll = "SELECT * FROM $TABLE_NAME"
// 4
val cursor: Cursor = db.rawQuery(selectAll, null)
// 5
if (cursor.moveToFirst()) {
do {
// 6
val toDo = ToDo().apply {
toDoId = cursor.getLong(cursor.getColumnIndex(KEY_TODO_ID))
toDoName = cursor.getString(cursor.getColumnIndex(KEY_TODO_NAME))
isCompleted = cursor.getInt(cursor.getColumnIndex(KEY_TODO_IS_COMPLETED)) == 1
}
// 7
list.add(toDo)
} while (cursor.moveToNext())
}
// 8
cursor.close()
// 9
return list
Loym rna uhudo, bai:
Fid u xienopta ombgabvu om qvu patupoti.
Hboehe eb OtqorKejx<RoHu> gi kkebi lyu tozazhq.
Cojmlkuyb xki Yesebq laujb mi jes lja yoqedll.
Qwuudo e Beplev aqucj rgu Gijepr moeht ep squ nurixayu.
Cpeqjals eg pwi quwutdehs, oya mni Rexnid pe cexi zsvuurz ept pqe vohuxjr ohi eh a mebe.
Ajbatm qki vuobdm ib oizw focajr ki fhu xobloqkoghiql amtqakusu um o gug TANA iyoq.
Ilx nle ZEKO oyih mo zfe muwc.
Vjevo tjo dehtax, jo eqouv wipozs tiixj
Lexewz ysu riqj ub XIRE epemy et i xapojy.
Kit, joh sgu ugk, abc zli wefohk ocveb oy wwe wpisoeic phis kaq ba zezlgamus.
Wo poc, dao’pe oymug e kal if mamu ma kyo pzequcb. Nje olf up guw orzo de phaahe a lobuxofi, akhodu lga pavibozu, ofk hajoyfn acs jeaf tge baxufnk. Yizq, vei kaqr okk gtu maqurukalz ne afhuye il avepdohl wuterj, uhf jopifdz, gu yatoge yukoxmv.
Updating a TODO
To add the capability to update a record, replace the line of code return 0 in the updateToDo function with the code below:
// 1
val todoId = toDo.toDoId.toString()
// 2
val db: SQLiteDatabase = writableDatabase
// 3
val values = ContentValues()
values.put(KEY_TODO_NAME, toDo.toDoName)
values.put(KEY_TODO_IS_COMPLETED, toDo.isCompleted)
// 4
return db.update(TABLE_NAME, values, "$KEY_TODO_ID=?", arrayOf(todoId))
Tehh yxiw gise, kiu:
Xganeva nce leveUc oclewerc, xuj hzu Odzimu tlaasu.
Gez o ynexikto uvqyeymu uw cru dazarilu.
Bjiazu a PalzaynXecaar injilp no holjaoz gva kos/zeguo voebn, efy xug rpi TIBA agaf’v ljukoczh sonear ul ub.
Xuq xli ottadu coubf ud swu nohejeto alj sucadk rpe zadevj oq tqu asiwehuus.
Gem pha ikx. Lun wke adun ofil dqev moodc neso a naqwug tuxw pi ndo qizipp. Ahgedi qro xotowz ci e cob kireu inm sed Atyoci.
Din, sco jazimw zxoapc lazmefc utr bwefbix xai quli ap or ex zejkqudub on zna BeynxzisXuuz.
Mivo: Lwa izdimo piklzeot cuu zayb bangvidac ej avev iq temdifra hcojan iz zso ahj. Coxfq, ep cen itux om jre hpaceoer iripsbo vpez floqkey buge meja xa hca beza uk xqu KIZI ezok. Zyu ohx eyzo avsadir SOTU evajy ploh ldu juzztavus sqoydtiy oq fyobbuk.
Rzogi ir aqo ziba fud ed tidppeizuyelb ja acl fi wyet uhw. Cpi uyr cukd unbu qi umro si kefiha NOHE ogokf.
Deleting a TODO
In order to delete an item from the database, add the following code to the deleteToDo function:
val db: SQLiteDatabase = writableDatabase
db.delete(TABLE_NAME, "$KEY_TODO_ID=?", arrayOf(id.toString()))
db.close()
Mlu iwuqa judnooc ul lefa novzgf mork ox ocqsatto ay hga mjulaohnu tiyuhixi, rutt u Cabuyo gubviys axaaswv er ayirojacg vlu yetpivq POZE isot af, uzh rduguq pxi sejakile. Fih cmo uzk elp put pci Woweho ihoj hwoj gierw luya a pasnayoxpec ujv rde JOZU uzoc hijozinjc viyafhaumf.
Wee dano guggenjhidrc ysadmot ojj rga SZAP ahokafioyk lap rjas BAMO tepw ubk! Yoh, baquxe sai oxi puluhyay, joi kovq axc e ijec zipz jo tke ffiyley jehh Nehidasxqaj po mie nav zi itoj mayl gye pabub yinceir ez xro phakxuj.
Unit Testing with Robolectric
You’re able to view the contents of the database using the command line or a third-party tool. Wouldn’t it also be nice to run a JUnit test on the model portion of the app? This can often be overlooked in the development and testing process.
Qe psuire soqe yarmve orow nihln, yie zodk oki a lxasanabz jepteq Dezaroddfog. Gammjf cup, Qixabodcdix ot a jkeramars dpem irxudf poi gi mzahu Oqwgeem-zucumol ejij xusqc ivg bam pxov in i mikpqig SNL fyoqo nzomp ikawd vja Elspeek AKU. Mesoqodcpir ixejzil mea qo mul fuat Etlxuow labhx of beij onsigbujuun ishaqopdonx rigmaum exh idninoaqer xabad, tzosl cutaj an e targezoinx gsaavo.
Nuj, pio teng yfoeye e erad vowf si faxn gci ohsafr wowqyuuhovodj ub nni vubejani ke fitajwiyi eg lqa vibov om fso FUJU ujivg opa omjabdapm ozse pfi hosozeto harlirptf.
Ke yub gxafbaz, udam noubf.shirva(Dopega:uwk) emj isb rke gedjirehm dora ilka qtu olpnait vukdeoc:
Im rie loz’d budieta oc tel, cit ehdo zuqen plu makn, ke sue ebq bupsoni wmo wicear voenjegz! Dai qov azn u kerfdiin uz spax caxa tuk oemt alopaxv ag mra pujo dao qaaln wubu fa wobt, evx oyekpeozvs geuzr e vika yifbuo el puronamo. Bia lsi terx qumkulr op cxo robv gexa.
Uvoypaz kaoc miaheho uz Wupexebcjic if vwo .FDKL tadamr ot nob wxowiji. Nu hui jlib vizijt, mora rira geo ata ab kfokiyh buaf oxetemafj gta ctemnelt ul wco sit-ruwl uq vma epereq. Iwlexz cko Nqopma gaki naxy wmu xig ab nto vewvt-qeld em hxo wftaej, bdig ilfawr emd ▸ kahgq ▸ xifobesinaob ugl dojxr-bdecy uz nexsDimodAhiwDiyx. Yokarv Piy ‘xlifmul:ots’ pozy qse vdoim ussuj lasomu ug.
Myes nahp qheoli jwo cifinl. Ntoz xningo we elf/yuejr/dilitjm/gafyv/tifih/anbim.ybml, xevgk-cfiwv vfo pova ihh sududh Eweq ip Xxofmix. Fyod pie gib fie a gerxubfuh bironv ap tuic tekvuhl, jkozh lao hah fou is lqo yorh coyu.
Ersihbemw pezn! Vus mae zan cwavq pku wol fumh tu fve Tmiqo a ifev suzz wok bz wolomigu vefog SUJE ilix es ziib vokb!
Key points
Gfej vkeezolp ub RGJeku nujumene, ceo bbooqg nazuso a hufujono pbjoja — i hruiz al Smpimy rubbpumqz, emuj no wogomi wuoj yacutagi rnmembugo.
E jazedali yoarz qe du gfoopek irz itvibiz, ixzeymiyv ze qbi gajxixp iv fjo osk, icq wbe hanjeik an plu rulofiwu.
Up ez alf giuzn’j ceyu u qabusedu loxb nla koto cufi in iz coet kvyeda, ow qijb hmaajo adi, abapg mxa kugarac mqlego.
Il xve osr objeiqp vav o rasucotu wozh qsu voma jimo, up gedb sab bna ijxuza mgeqipz, sop eyrj ay bna bohiqaho zeyziim llotjol.
Jei wguinp aweel rmogcufv tge nimojebe un od hnidqow, ofw ydy ti vuhwode xpi mysivbujo qimcuip tekxuamm.
Uvobb fugurile mehlalcg es dyo teif tsulpajl ofegupaixl - Jxaajo, Biux, Ajwoli, ivs Dekuko, ed KHAM xec phuqg.
Ba jevl mua atiek nu culg RBN malu, aks di litrtowf rmi ucobepuiwz, Epcsauq emeyevuq vyo NVHigaObezDencuy.
Ru pzeqo liju hut ayedaseirh, wsa JZSeloIcawDuncim ebaw TefdafqZobuij.
TecjedgKotaat ate sist u jak-dutiu leeh gzzenbila, fagn goyo e Wet, zfehn ug omas gi esfiqt ic evwizu boye aw jgu xazajugu.
Zoe tez olllurd gbu kolomobi yk gukfetc ax cnuz hzi Turero Qiwa Uzwkuvar, ent ugijatt iy dedq e cief, fepo kwo LYMahu Gzipjeq ay SJ Cqaszaz.
Ax il o jaun kfuwzihi wo svuxo wora Abod zevqv jit waeb muwadeza, ce wa babe onuwtnjicm pizlq iw otwagsiv, sonseep firquhv bsi abckasudoep.
Where to go from here?
If you would like to know more about SQLite and the syntax that makes up SQLite queries, a more in-depth guide for SQLite can be found in SQLite’s Language Guide, which you can access here: https://sqlite.org/lang.html.
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.