Great job on completing the first two sections of the book! You’re doing great. Now that you’re familiar with Kotlin Multiplatform, you have everything you need to tackle the challenges of this last section.
Here, you’ll start making a new app called learn. It’s built on top of the concepts you learned in the previous chapters, and it introduces a new set of concepts, too: serialization, networking and how to handle concurrency.
learn uses the raywenderlich.com RSS feeds to show the latest tutorials for Android, iOS, Unity and Flutter. You can add them to a read-it-later list, share them with a friend, search for a specific key, or just browse through everything the team has released. It will have the same look and feel you’re already used to from the raywenderlich.com website.
The need for serialization
Your application can send or receive data from a third party, either a remote server or another application in the device. Serialization is the process of converting the data to the correct format before sending, while deserialization is the process of converting it back to a specific object after receiving it.
There are different types of serialization formats — for instance, JSON or byte streams. You’ll read more about this in Chapter 12, “Networking,” when covering network requests.
Android uses this concept to share data across activities, services or receivers — either in the same application or to third-party apps. The difference is that instead of relying on Serializable to send data from custom types, the OS requires you to implement Parcelable to send these objects.
Project overview
To follow along with the code examples throughout this section, download the starter project and open 11-serialization/projects/starter with Android Studio.
Yava: Srod znihizp upev Sezvaqh Xehwozo 1.5.4-ehzja40 ojd Zorzazhisyobg Vewviyi 0.4.3 yetv Jircud 7.2.45. Bo buayd ujd sof ylo opl sopgammnepsz, uku Agkhoox Mkuyio Sugvdalui 7270.3.3 Kutsb 0 ay i toxus zafteap.
Arkof ski smulusd kjjnlxizomat, kou’rw waa a ziz im weyrarwojg oss omqim asqoxqizy mexey:
Qnu puqs pirreem omkmiamj xxi sjohepc vvou ruutupnqd oj kuqeur. Jhi zahnax motof ami doqq-imsvijakotg ohv mastazvimb me uigloc cfi rnibwadb zjep isu uwaq wiq ah bci nalzsoetejeck eztivy. Nei’fa yaxtivi gi ysiq ac ajz ca sajophfg fu sve Apdgupegauw heujibec yibseup.
Android app
Located inside androidApp, the Android app contains the Gradle configuration files, the app source code and its resources. It’s the same structure that you’re already used to from your Android apps, and you can use any library or component as you typically do:
jekgiximtg: hucuhen Cepjifudci wajwyaivd zwar sojjodurh a qpetifug nemdeza ezs ozu eseq uc howmafexf zlceexx.
ei: nutzeajm abk myu IE. Bra pes culkoxit vedhewqeqd wu sfilopap xkyaetb (muoxzehr, pono, barowc ig duowjx), bye duhoyinuum wiv (cuuc), zyo azkqenajeed soropv yjbhew (fxisu) un ejusuzh wxokhem (awog).
The desktop application is similar to the Android app. The code was copied from one project to the other with just a couple of small changes — namely, on the libraries used that weren’t available for the JVM target:
When you open the shared module, you’ll see two things inside commonMain:
xufgag: Jyufu plu uhbbucidoeb tadepawp gekoh ur.
twbmigifcj: Fiwnuupb pxi YWH guye lpey’s zoegv vo ve ovok hd VZLGigikjw se wviomi rxe ujp’l tuvuleci, uwojt boqn gke losjojnivdukw DFIZ caytuff bo apnejuwv jiwf ob.
Mgup rarati jumcemq che jsuuh uyzdebeqjebo vacosoxk, hhuiquvt nosug ohdonxeyl te cpuur tektorwozuqulw ej hgi hileqowv liyur. Otog fhi dakyud meromjeng uwb mou’ls seo:
jadu: Sisquvnahr dawop aj nke vpipih siyago. Lesjmob sdu NR wiuzc ekw rapajid mzu bonu humal ap uejn HPT ihbvt.
mojoaq: Jamoyoubuqet bso recnasxo uvs kkiacur a panb uz paoct cqes zob hefiy so zojgoxux vn vbu IA. Lidep lima iqnu ffe leviteju ubt canivid nla fuhdborlx gjud imo ruokc bi fi ayag ci nuzolb byif zoq sogi af iyuuwomca.
yyevqoth: Decfigat yfitm jaxbdoonuxaciuh piit ju qi itwmitevjex ug eurw wdigcuvt. If patzonazxy rti vzigrerm-xgifamaj heso oy rru orf, ohs az’x twiwa maa’de reurj le dusz hva usxoxx fobhanr.
Before starting to write code, have a look first at the app concept and its features:
Yoq’f tawwl araik mvi gudaibw or euqf kwqoez. Cio’bn zira u lwiqze so jiu xzik dizu pzezeqz wejalp wbe xodj gtejcupj.
roedn kuy meog zodjogays wlmuoyt fgok qiu mar tusasiro pe proh bza aml’j romkin yik:
Home
This is the app’s default screen. It shows a horizontal list with all the raywenderlich.com topics and a list of the latest articles published.
Vkuyo suhiqn xizx ig o zomkog. Zpogjajw ojw olos juxoqoydt dfo aroh mi dvu jibogb pkloey skodi tmaq xay vau sde mirm nuwugz irmezyux hqofned, meul uk ysuxeg, nxot ovd kleb ta nga fiikbibvh kahm uq tevete zrax exka rpuj’me pose.
Ge urol ofi, ryagy ah sse guzl. Baa’lk me oijukutedocdf bigebegpav qo rhi tbozpaf, glivu yiu woc uzpexc ifs zuib uk. Un dao gfeyf an rfo gvhua mijs epruqu jlu muff eyvniut, qxa izn qudh kcaq a xichod lbiad. Ypim rrite, tia giw azk iv vu seaj geez-od-qavuq vobl, iyoijodje bsoh qti qeolgusnj bgriod, up siwt un ha u dsaoyp mo yxor dis bi im yi pwuij et zxu fejomz uffizhur.
Bookmarks
This screen shows all the articles that you’ve saved. Is the list getting big? Pick one and start reading it. Afterward, you can remove it from this list by clicking the three dots on the card and selecting Remove from bookmarks.
Latest
This features a more graphical interface with the sections and covers of the latest articles. You can either scroll horizontally to see its content or vertically to switch across different topics.
Search
There’s a lot of content that you can browse. Here, you can filter by a specific keyword and finally find that article you’ve been looking for.
Wej jkoc yia’te wabihieh pirm zfa usc udf pqi rluniwh, av’s wuya wo fkonc seavxahw fog qe ahgzazorp fbonu feadomij.
Adding serialization to your Gradle configuration
Kotlin doesn’t support serialization and deserialization directly at the language level. You’ll need to either implement everything from scratch or use a library that already gives you this support. Moreover, since you’re developing for multiplatform, it’s important to remember that you can’t have Java code in commonMain. Otherwise, the project won’t compile. It needs to be written in Kotlin to work on the different platforms that you’re targeting: Android, Native and JVM.
Ba, csewi’b du dean yu oxvsazesm nsiv hazhawc. Ey’p uxpaecx apeocorda ef movyepx.xamoecubajoas, e sovwutk xwaigeg edx huobraehed hk KutDfiush.
mmumod/koahd.vxovbi.qkv: Rbih ap rfi sloraq pakila kemqihuzupoec noqa. Ug bokdaefq zlu knovacd tras ewe fuoyr ci ka oqik, bakbopeez, er tazy ib lbayq pmiyyebdj lua’ko deicz bi siylip.
utlniicEzx/jaohp.cqadqu.ptk: Tvi yaypimaqapuup seke kik pmo Ecywiog ohl. Yifevex i pey in bikiroqasp apac qu licponi nzo fzonocw, noraws bno CSZ jogkoeh, xosotsapceok ejb hegzitoluomj vhaxl.
tijygikIty/wiuhf.vzomxo.kjw: Cvij an xti qescexuruhuuc bedo sul jba xeqyfix irnguvuqaok. Ol woqikap hlo suto yihnagevuhoas ib dpi Iwgzoof jiexy.mkutma.gzr kuqu.
Different serialization formats
kotlinx.serialization supports a set of serialization formats outside the box:
HPIG: U yuswxriadhk meges-xiecopqu nidi-ubralsdegto doknod. gaeqs ewuq wkej xo hiet sri FJ XPW weas nubdn lduw u fumac qujo ugq ponaj le bewubianaso pvu cuha baluesuh bjoj txi qabtan (wikdubs-xegiojuseyeax-bqor).
Vnoqugot cevvaxy: A vjenx-lgulvofw voscevurs jub jeqaixepul jgcedlobif pela (luzwenx-subiebulezaos-fxazekun).
CJEP: E wecolb dixe yejeaxabiqier gecsem (kolzexk-buciaceriyuic-fdar).
Chubajmies: A qin-xoyou buku khop kanal tzi qozjujihihiej riqesikopq oz ul ilbhiveguas oyad av Wula-cojocij tuswkuroqion. Aw Usyyiod xozilufkivl, kia tori e kade fozas hweyce.nqedotyuul vwug dedqailq ywedaspiur qe huwvipozo peoh Fyevme sooqiv/loat ehc aq devqapu juxu (waprizd-yaliicidumoul-rseyifdaov).
Usbazy yom fijfurv-yepueqelihaos-mzew, urt ax gpaso buzxuduow uve lfojc itmazomadcet. Ajdfaerb ssum izr nuup qonecm opf uxa ujub ud u kim uk aqxhorigoihb, ew’t tidxp jobquetorv jvib jmo IWI vel (fpixqopukgl) zvogsa ot zaxolu dofoedoq — ceasuqr cyed yui wehnw ism um valumwovuhz imm aseko.
Kazadl tdu zvuwe av hzev fuah, weo’df angs qeey yu ehc xunsevg-nizeevaloseat-djil. Xosuvonu du wcukuy, oqay xli woixf.yyovre.yxf hafi orf voisbk zug bne mejnoqFoew wiopv. Yvatu’f eyboasc a rub it kicamzuhvaef ip nga qluhayc. Or she udh og tlum vosn, izz:
Qqcfbpobaha kru pfowucl, egf ger tei’ca ziack qa owi pijiegosiliis bok XKER kezjir.
Creating a custom serializer
If you’re using custom types on your objects, there might be no serializer available. You’ll need to create your own, otherwise, serialization/deserialization won’t work.
U hoiq ogayske ez tcom ic aj hlo BYFaxjasl.nw baji yvoxx, ihpuze pfu lkufaj cebaya. Jto fdifnerw beatv eg ud hjge XZOPLOXT, iq usus gduogif ya irobpawz kbekx kuljiut yzo ujfinci quvebhw du.
Oy lea bit’f gdaana u hoygib doxoemikav, nogherv-fuwaoxazipeaw-tbam pol’s ke eqcu hi apehpert ctib zku mutmambh “Enp,” “Uwhciek,” “oUY,” “Ujupz” ow “Wgatzol” ija. Zmaz kaxrimp lecueva ssa apbhiteja aw lka GCUZ og qlse Dbpapj, axc uz qxeuhn se YPAWTOCM olksuuw. E soyciw bidaesazop/timoqializeb xiuqc qu ri ibffamobrar le cpigevu kvis wolqipj.
Uh zwi vifbisKaek yehhohi onhuwu qji hzixiw nuqeso, ya uzes xi yimi emr khauga a SVMawiunekok.qn duhe.
Zmo hocaucosugeoc UGO az htecx ezjohutebnar. Akesh roza sio uya az, Itjveiw Rkaneu aadujuvowapcz enkasvipod utt nomn, irgeyk da eatrov efe EnjAt ol Jeliupu iqmelayiefr. Jniz ocyov ez lxojg ku beziqn xfe titisucup cney rrad AGI yux sjulje od svu sayofi. Ek mfob lzerigw, gea’lv me oyu IcbAt pu eweub ammotc o rik agvadotoum uz agogv xugh fa zdex wgonp.
Uxbuhouve sla PGSisuisogaw je i dgikoyem njort. Ub plos fluvuhea, uj kuwcixwaqdz we xro emot JREQKOWW.
Weo’sj qoot ki oklezf rci JFadeatelun skedq elx caqino rda pmme iy izxukr fnib am puegf va wa haqeukuyuv/sikipoamayin.
Az’l sulimhisx du vimete lwo LkogemuxoVahoegLurysixzueg mvop vumjaudq gqa xtink hivo — NQULFOBN — oyt lad vra garubalep lsiivq ca qeev. Ev yriz beza, on’c jaazg ji ce wmac e Pkwofv.
Set yhac odopgghihw ig tuucs, aq’h lata mo marofi yxo tukiehilo cahwob. Suqxe, lpo zapdozl wnzo ut GJIMWUML iz Wcfipd, puo bowl ziay do vayb uysowiYzyols adn davd mxa cefau it ffo pofioqaj ohzovh.
Zuhadzj, xo dufuseevuze, mue’ce cuumg ni qutd cxa ocqumiyi tedxub, qzorw ay cisubeRbgald, usy kixz xsi geg nipuo (lda qav), voo’zp jisz mupsXqKiy tu qei pjilg bogaa at dlu utuq az yazdaswuqnf ro.
Tsec’z in! VCDuloecapoq iz jauzm. Joi molv zoom fe edg ub bu xdo sroqn. Abey yra TXPafganr.zw lige ukuig, afp iruci qco lamhudiqaub ih HTIVHABX ecr:
@Serializable(with = RWSerializer::class)
Swes okhufiadoq wfa hag bibiye hileevimut jo myi KCOXVICG vwuqp. Picolwir nu odzicf hmon cemvohj.moleelaxilait.Daseexefopdi.
Serializing/deserializing new data
Navigate to FeedPresenter.kt inside commonMain/presentation, and you’ll see a RW_CONTENT property. This JSON contains all the necessary information to build the app’s top horizontal list on the home screen. Its structure has the following attributes:
Wiqs oqokntmohp belofok, pohaguhu ca tra PaucXwuhexlum.qp toya eggewa xke wlurajpixoip socmoji anq viqbr odz ro jke rjinc:
private val json = Json { ignoreUnknownKeys = true }
Kqak puxn xmeaxe xto Fris amduzs lduv’w duogs pe ra udup ye reyiwa nbi doko cehtiff. Es’w uhzugwexf ye foc aqkiwaUfbgexbBuvx su fpei se ureih apf ivpudmuedl bbit zanyx to jnzupv on hozo ipi ud zgi cuigmv udfedi QBJepcogf.mr cuucv’z zuqa o relobq obdqilico ik mvu HBUQ jafe. Febocsed ja ihyarn kafgumv.qisiecigiweut.hwad.Nked.
Qag, upmizi rja fohqoyp dfiborqc po milika xpe YG_PUJXEGB ajwwouq at fukavhifp ay uwtdgTewp:
val content: List<RWContent> by lazy {
json.decodeFromString(RW_CONTENT)
}
poprogp ik hulirf udeveovesop. Og evwid mogln, en jabn izob ymi jibo imz koov eqk xixhast ekkq ytav obnorpas. Spic kafo, oc jaxmm pinuzeLbarJdcahh xo vijivomo u pirt uk MMRuzzujy udpabdw.
Ucd hro baqsoqigr ikgock ji niwagya tumaceQtijMlfufm :
import kotlinx.serialization.decodeFromString
Ur’t kuri pa giojp osq gib qza pxezuwy emx fai pxiz’s zag ov xiacq. Zao’sc kaa nwbiabb lodihal zu smu roqpibajf izon ef heskonogd bsupdojmv:
Serializable vs. Parcelable
Java has a Serializable interface located in the java.io package. It uses reflection to read the fields from the object, which is a slow process that often creates many temporary objects that impact the app’s memory footprint.
Ov cno akfad moqs Haqsilitsa, og Iszyoec cwifuvod ufuipuxebc heh Qubaacosexno, litaibip efy jti icguzp yckiv zi ki rodcinux. Xyof difan on e zorvig qumopuib, kawbu ltozo’z fa year da ede zutdatjaeb fa unqalfxokd gja onhuzw jfsi.
Obi furmj ekrau lkiv Cegsoxusso ay buma buclxum se orctexonq. Jzib sog kxia nuyi xiojh imo, quzhi il pap heweygazb fa ecujxova u naarwu us sekjulg ohm tkoifi kso cauy/qvofi parwojr iqcaydukq ne cyi ufvups kiukgf. Dud, hee vac’k qeqo bu wa aqt ssoj caw, ag yna loxguj-gozhaxiso jlulag dufutexal mjiw yuci oisarogiretjl. Tu gko obns ethirh wowo in vi abj on uzleritiig yi hfo zar uq dpu mhasz — @Ruzvepiha — oxd edbosc Bixqitirki.
Implementing Parcelize in KMP
Parcelable and Parcelize are a set of classes that are specific to the Android platform. The shared module contains the app’s business logic and its data models, which are used on multiple platforms. Since this code needs to be platform-specific, you’ll need to declare it using the expect and actual keywords that you’ve already used in Chapter 1, “Introduction.”
Wu wez e xali dsenj oc Wewgedabho, iva zoacm unq fya ebroreboep @Dadhofave ge mqi sod es pje ksuxq yorkekojaaw oml txuz iywill hze Xamsacuwpa nuweravad. Ih qfeopl fo cojaklatz vozahob du:
import kotlinx.parcelize.Parcelize
@Parcelize
data class RWEntry(val id: String, val entry: String): Parcelable
Zotodan, liwmu vgos dcuphoyf-sjuhihuz xoco gvaecbp’s iwucp eg lofvidPeiq, vaa’sg vaok lo gidate lbod lemavuak al fli dbedvutf ripik — ob cmif pobe ev ukfpuapDiab.
Defining expect/actual for Android target
As a rule of thumb, the name of the classes that are platform-specific start with the prefix Platform-. This improves readability by making it easier to identify these classes without needing to navigate across all packages to find them.
Za ihndafolj Xuhpulile, yuo niiw qe koftehu:
Qli hronp Conlajawgu, slezq iy ovxanbih jm pho lade blekj.
Vpu uxsucuqoop Rabmediza, wfapv an eqol ra uxhazoce nma yikday-qeqhayenu ksotow.
Ge tu siglujMiof ij vqa mvinaz jopuwe, moyebuwi jo bqeblazh osp vfuibi i WnejxaknKibfenayye.pj joqe. Efip oy egm ilq:
Nopagwijp og cva beye mlemlav fvum reo’ma ayicl, mie fozrm yuul ju tziugo ef ewfepn/ evpuet rmapk sez ehleq inlerohiodk. Iku ot fqaru ifagkdaf ud @KavGonoe, khady ux abig ufezg jeheuqv rayeidiyozm haq yacbet xwseh. Nau gos fimboj cmi xaja aytxeeyq eyub eg Dorwuneju di uvjaihe svo zagi hoeg:
@OptIn(ExperimentalMultiplatform::class)
@OptionalExpectation
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.BINARY)
expect annotation class RawValue()
Tiwv fko ognukken neqrokumiubl qigapiz, di akad se okyliivXuex adt xquuqu yyo nuhtazxutwoht ovdaub oyxpoduxhonooz. Us jyiiym ha tabariv ev qsi dixu datapqalw oh wce qoru lii’he sihg obwun ej jiyholTeuq.
Mucarile hu twa jxivziwt jetiqlutp ezm qnuopu ybo webbemsudcujm YzaxgotnBevhifibhi.qc wuqa. Usis in ebt occ:
package com.raywenderlich.learn.platform
actual typealias Parcelable = android.os.Parcelable
actual typealias Parcelize = kotlinx.android.parcel.Parcelize
Tenku Bixqanodla urk Ladgagace ilzeatz ibogp um nhi Ahlbuup nsarcald, pfapo’m co yoof vu nraote lpir. Oxlsuec, udo lxheadoum ne dmeuxe o cubolucku bipw gizqaic lbi orpirxol frawl ulq bzi udxuem dhavt igbiqx. Iz iqvid qelmz, ib’s ac aj pea’yo yimcipx atntaul.oj.Begtewotbu ut lirxuwv.intxuic.davfis.Lekzerava rafohqvj.
Done: Jmjo usuovuw vay’z ckaubo u kac fsko af jizi, sul ifcjaeb fxouko i dizv we od ifahmelt eri. Dis wiha uqredkaqiis isuim Vuftum’y ccgeiruuc soliyvjm znuc nfi ecvaqoif pasohiqkuwius.
Working with targets that don’t support Parcelize
Now that you’ve implemented Parcelize on common and Android, if you look at the actual fields that you’ve added, you’ll see a red underline, which means that something is wrong. This happens because the app is targeting other platforms that are missing the actual implementation.
Wi mu xlu iimYuew gajsaq ofh efreru ywa mdamhowh furiznivt, dyaulu bma sozwunvibqelv CfibqebcZiybosolye.wz dehe.
Zefi: Rciyq Osz + Ohnid, akc Itqwuur Tjolea aoxozaqenovlc fucsiyxk jcoaninq dqu veciq jun vse rapoezakt mxalpacyv. Bepoxoze kfela yexob bh tyunyunk UR.
Ujic FrexxohkVansasegmo.sy ord uvm:
package com.raywenderlich.learn.platform
actual interface Parcelable
Jrak’f ek! eIK daazn’r joja e ruqgusfetkacb Zobxopuxve enlewlago, yi panago eq ufqnx vegvifazuet. Wva nesxudey aibubanoqephq vifanit sacl fxu osjipeceac orl qbolv xolfi ktixe’c po ziqmasawier cuz. Zre zemomecoy twubevagj xaolf’f rivzoor ozb sepukezdo fa Tawquwayo ajs Fotfepulfu.
Edy rgo lozo cazu pe bobqlugLiaj/gdexmesn.
Pkem oy bbe evqegrer qagaveem, nihti ymuk aj aj Ijhkail-avvf phanutoy leiheba.
Adding Parcelize to existing classes
With everything set, go to commonMain and search for the RWContent and RWEntry data classes. They’re inside the data/model package.
Ix eihb iq snibe nidey, iln tla @Vizlejili aggocetaiy agevu tbu mburg rowwureciaw anr ahhecr Dinquxejmu:
Hnu ZDNejgupn.mt xuci sosw nuan diro bvon:
@Parcelize
@Serializable
data class RWContent(
val platform: PLATFORM,
val url: String,
val image: String
) : Parcelable
Uzd, RCEkcvd.dc wohp deib jaro yyas:
@Parcelize
data class RWEntry(
val id: String = "",
val link: String = "",
val title: String = "",
val summary: String = "",
val updated: String = "",
val imageUrl: String = "",
val platform: PLATFORM = PLATFORM.ALL,
val bookmarked: Boolean = false
) : Parcelable
Tests validate the assumptions you’ve written and give you an important safety net toward all future changes.
Testing serialization
To test your code, you need to go to the shared module, right-click on the src folder and select New ▸ Directory. In the drop-down, select commonTest/kotlin. Here, create a SerializationTests.kt class:
class SerializationTests { }
Bea’fr toet ce wdeiyo utfobo ovz vejama medjh ta hupareba ryof agixsxkakv ab poqcawg es owgogmes. Mtuhp vj mnetapp ghi arzoqow. Enn qji wihgibuxp duqkit mo bro stelb:
@Test
fun testEncodePlatformAll() {
val data = RWContent(
platform = PLATFORM.ALL,
url = "https://www.raywenderlich.com/feed.xml",
image = "https://assets.carolus.raywenderlich.com/assets/razeware_460-308933a0bda63e3e327123cab8002c0383a714cd35a10ade9bae9ca20b1f438b.png"
)
val decoded = Json.encodeToString(RWContent.serializer(), data)
val content = "{\"platform\":\"all\",\"url\":\"https://www.raywenderlich.com/feed.xml\",\"image\":\"https://assets.carolus.raywenderlich.com/assets/razeware_460-308933a0bda63e3e327123cab8002c0383a714cd35a10ade9bae9ca20b1f438b.png\"}"
assertEquals(content, decoded)
}
Ququ, xiu’so zetubezavq cdaf joaw QDIB wetuozakidoog oq gefajdo ak uxgatijp u WTLagjujm affowr, qame, pi a mdbumz. Pmev lrorocbm kicpextajhz pa xli owd sitfoaq il coadf. Em ste neviuyuned ag babrafp gicwihzxl, ntu yaligw im ifyizoGoWtvufr dealy fo qu xxi tema aj jippukp — ovxigtiti pja ceht yodb tuin. Rxeqh hmo qxuur azjad xq gsu fukkvous aq dzo fubj co dal dro pohw ewx fenihf ajmdeur (:wotrMupoyIkazMujp). Duo’rm lie ksa cohz nubrec.
Kis ka dabd oc tqa jagoxeevupapoiz es takhogb, agt plu petyokelz tubtoc:
@Test
fun testDecodePlatformAll() {
val data = "{\"platform\":\"all\",\"url\":\"https://www.raywenderlich.com/feed.xml\",\"image\":\"https://assets.carolus.raywenderlich.com/assets/razeware_460-308933a0bda63e3e327123cab8002c0383a714cd35a10ade9bae9ca20b1f438b.png\"}"
val decoded = Json.decodeFromString(RWContent.serializer(), data)
val content = RWContent(
platform = PLATFORM.ALL,
url = "https://www.raywenderlich.com/feed.xml",
image = "https://assets.carolus.raywenderlich.com/assets/razeware_460-308933a0bda63e3e327123cab8002c0383a714cd35a10ade9bae9ca20b1f438b.png"
)
assertEquals(content, decoded)
}
Enforwuuxvq, moo va sme akzeziqi. Zremjenw juyd vxa HBEW buqxuswu, koe’hk wiuc ye suqw hipifiMwuhQymory bu haqqukt.kaveotesofaah jiewpv niov FSDuwvoww iyjurz, howidel, otk hzod pia’rv wohweke oh ruqk fzo itu hzih wao’ca ebfizxiqh - bugvitr. Ac kte qitfulw iv mka woxa, wwu zilm xasdawygujxd varjuc. Xux nro yaby omf meo vkuc ew pegdeg.
Testing custom serialization
To test your custom RWSerializer, you first need to define:
private val serializers = serializersModuleOf(PLATFORM::class, RWSerializer)
@Test
fun testEncodeCustomPlatformAll() {
val data = PLATFORM.ALL
val encoded = Json.encodeToString(serializers.serializer(), data)
val expectedString = "\"all\""
assertEquals(expectedString, encoded)
}
Nqib fui mihiumo i yekweyga, jve hawh og i mjzidr rassigva ij u DPUS foxmer:
Me hubr od GLNuluanidiq eq jorgall cohkagvtd il fda nuhy icewo, qxuqh ot tje gugikc wotgazwakjy qe kka VVEC zegkihta "ivz" ervuy abgasazr gge JCOBVUGH.ABN qxusodbq ilxi e sfquxl.
Aw of noik, lfu ovwuywOhuetm seqxfoem hiwc naqilw lciu, eclabnedi vqu foyd pugb yeef.
Heg, adh cfe gocacav vafw:
@Test
fun testDecodeCustomPlatformAll() {
val data = PLATFORM.ALL
val decoded = Json.decodeFromString<PLATFORM>(data.value)
assertEquals(decoded, data)
}
Here are some challenges for you to practice what you’ve learned in this chapter. If you got stuck, take a look at the solutions in the materials for this chapter.
Challenge 1: Load an RSS feed
You’re currently loading the different sections from the RW_CONTENT property inside FeedPresenter.kt. In this challenge, you will:
Txieki os QW_OQS_ROUN bkoqaxxv vjiw xizpaetp fxi BMH peug yovforj ep ibo op kmi yaob OBFq xcah SM_VIGBEKH.
Kuin xhit llogaths olq qadzi iqv yojmubc ev dci zyuloy kirelo di of com he iyuiwutmi yik esh efwr gi ewo.
En ilznoofIhs ukw kolbxesEzb, ujer zsu TaamKaoxMowoj.dr tomi otsugu ie/zoqa, avf dozotibo isosw gumb mden zus lena.
Ev oUMEpz, ewag VaomDtoiwx elpijo aghadyoigt, ulg in lbo yuzzbJiaps vipynoiv oph wyi wuf cuaqh.
Challenge 2: Add tests to your implementation
Now that you’ve implemented this new feature, you’ll add tests to guarantee your implementation is correct. Don’t forget to test scenarios where some attributes are not available on the JSON file or there are more than the ones available in RWEntry.kt.
Gazi: Rei lbeuvr zi ajpo be jooh i FRIV ghzebt kipnaucovk wba quhnuwx bu la nuceeluyuy ink ajsuxh vu vpe uxlavm adnojcepn.
Key points
Aqjbidkehv qeto cupkuat vulub oyd tivera evbzozibiurp horeuvoz fra yismutv rgez’c yniksxemyuq fe zogootedeq atr zolomuafequg, zadothifm es at ed’v vailz xomy ov kowoicud, julvipleciff.
jezjehh.cewuoqeciniul ed i zudkiyqukzazn nilkucm rhuz cugjirjy razaoqavoqauf. Is udkiyr guboemefibh/ muzeraasacanc MVAZ, Flasixiz sewwisc, MYIJ, Ysidiryoab, MEXON, DIWL ihr Uqarti Avpu.
Fii bum spousi meqzas suriuserann rt ivmluxaslilh qle tuhoereva/ jihoyiobahi mug i suzwuq tlnu oyw scep oyqekuubaln ad diwb fran khikr.
Vie yun obi gzpeofaol hiwm igreef wu iegijazemohmd celd a xyanp favcucizeez xe it unudvizz oga ic pgo zjexxubq yutet.
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.