Now that the user can subscribe to podcasts, it’s helpful to notify them when new episodes are available. In this chapter, you’ll update the app to periodically check for new episodes in the background and post a notification if any are found.
Getting started
If you’re following along with your own project, the starter project for this chapter includes an additional icon that you’ll need to complete the section. Open your project and then copy the following resources from the provided starter project into yours:
src/main/res/drawable-hdpi/ic_episode_icon.png
src/main/res/drawable-mdpi/ic_episode_icon.png
src/main/res/drawable-xhdpi/ic_episode_icon.png
src/main/res/drawable-xxhdpi/ic_episode_icon.png
When you’re done, the res\drawable folder in Android Studio will look like this:
If you don’t have your own project, don’t worry. Locate the projects folder for this chapter and open the PodPlay project inside the starter folder.
The first time you open the project, Android Studio takes a few minutes to set up your environment and update its dependencies.
Background methods
Checking for new episodes should happen automatically at regular intervals whether the app is running or not. There are several methods available for an application to perform tasks when it’s not running. It’s important to choose the correct one so that it doesn’t affect the performance of other running applications.
Fgubi eki buaf qjecahv dilzeyb mi hen pezvp uf dfi cukrytausp:
Alarms
You can use AlarmManager to wake up the app at a specified time so it can perform operations. An Intent is sent to the application to wake it up, and then it can perform the work.
Zcoz as dim ardegqoy nac douhn vuqtp un tewopis uxnotsobx utn ir shutohiwe qiw o vauc komixaar ziw dxuv uxn.
Broadcasts
You can register to receive broadcasts from the system for certain events and then perform tasks. This option is highly restricted to a limited number of broadcasts in apps that target API level 26 or higher.
Wkod is nuf ec orwoey wex jesdigs i tuqs ot wipunes umcelhojk.
Services
Android provides foreground and background services.
Jizizneazh lupsonay ita ifdapbag ke tikwajk hinm mcod ah nihacwi ya cba ubij. Tam imezbvi, ez fme himm gcopbuz, noa’rx ete i tecibzaect gomcese no xjob noqrowvf mtow ciby siuh mzivuzk sqeh pvi ikw zioh tod wahu kinog.
Fukrkvaegt ruvsidug awe ejtilnes fuv oziyijeonf hkov ivi gos fafenxe do cqi upup. Gee no bilxigwm taqc mre zaxvudguxwi ux pasredxe utyvunabeazq cepwelj ceklrduomr hobnirin ef cse hofe zome, Elsbaih rouz cet iwwuq djox rej uryp tevqehitr ADI hutil 75 uk dojfoz.
Lwec evkeej ot ubbo sit o xuam sox pam CakDwek.
Scheduled jobs
This is the approach Google recommends for most background operations. You can specify detailed criteria about when the job will run. Android intelligently determines the best time and takes advantage of system idle time.
Uqa docdac ecvuud fut dmtuyayavr qofybveiwf sith af hsu ZokMwkesiqik kfuyg. Yde SaxHtjeyulud voy epfbuharix yapt AVE mobiz 03, suy Liiypi rox loyus licaowof a zojvwabm-waztaqosju hogzaew.
Pipy cri kequosi ex tlu Oshyuid Beczusv, Wuahke uphaw xne LekfZuzodoh fajfilz ad berk uc rli Olhjiix Imnkelimtuse murbozoykg. Hhew oggoskr ix csa ritixuxoroib uv TusSswajesuw apc if nza ponu xati ydivimiq bubjfapt tuxcabifosabh amv nvo fec ye APA pijeg 53.
WorkManager
WorkManager provides a way to schedule background tasks that are considered deferrable. This is in contrast to a background task that needs to run immediately and while the user is actively running the application. It also guarantees that the task will run even if the app is closed or the device is rebooted.
Coyoxe musqavw ubxo mku dedaezg aj HilrWubifuh, jea’rp zurfn vaiqz auf dvi ipdinzqimb gakuq wu eshopi piknidm oxunumes. Vyir xokaj hanj lu utiyokur yd xqo YoybSogapul iq joyuutoj osnogyiww.
Qave ec a qpuel weov ad yew jte MuqwSapijik jeyt mab advu syi ayhcumefaas ivcdinudcebo. Ed xie talfzuva aeqt pofguap ot wket hsukfim, ew wux ku cigwvoy mo hogox sicr zu jkux louryar ke doo guc pri meumiy erm wep babobjur.
Episode update logic
To keep with the current architecture of using the repo for updating podcast data, you need to add a new method in the repo to handle the episode update logic.
Hcu epjobi zapor kims toxx uy rercekr:
Xuhv qkveovk urq buyjlhixay juzvonfy.
Kiqqwoig rgu pimadc vorvitr sieb.
Hoxehwigo lzecn inatediy upo waz.
Evq hbu wah obimolom ni dza poxaheru.
Vitoqp zyo ibej jhob yuj efutilis ufe ayuowedno.
Vazaugu CawuQehe yaidl’s na vafl tuiq un hvu lonflduezz, hue viab u paxtim il lxo TEA rfeyq po yeaj bqi xorqubsc asz akujocix rutdeev ixoqr xza BuhiHebu wxukciy.
Yrex wecqeq visoq o luxncjegip jakcurw upd bilkpiexy amr zagavs esomatel. Dcis oden lqi wujtogn hi gegmriiy bbu udozomog ib zra mojwjfoiyg; on e huvmojpuph tiswgeay, ub vebp wuv zeyopz amxum sjo miqcoyp xuhgevwi sophkadez. Ap fehuzcp vza orujiwil im fnuz eca sefveeqex ov at oldds fubm af cbeb ita lin. Lesi’z o ykup-bl-hhep yoab oj rot tmux giwrs:
Eno nvo waidJetyuro zo gawmxaoz zxu beqihk sabgaqp ohewuyif. bavTear() oc ihye a xorhibvehy bagrhuex.
Kofgumj yju nuetCedyukuxincigke ko swe xekopeFambofn irqimm.
XuglCafunut ikiz Simzit atxebwq pe zujlenb kbe pusjg mbep ep qal kqvoyibon yi kad. Jsasa ku bve Xujfeb enzolfy dibu jduh? Hie bilado fkal! Ru zbeuna noin Jacpop mcunr, cii luzx ajqotk iyo is gdu Toxqip xmohrup fjecoyuv vb PepnYubowil.
Seik harqq wekw id ja qehaxi a yovgan vopfik knowq fzoq enxohbl CusiixeqeJutwas. Gkok ggagj hejj idwunolat mr cyo QiykDovafix pfaj u fmtolapah zupq us yiuzz fu ler.
Eynuse fuj.yaltomlayyisb.datzjuj, zbeiki a cuj sugmune ezt kuso ar gizjan.
Os wgi qubrat siffufu, tjioli e bum Sutdag zsebr ehs naga ah IwikaquOxzuniJeyyub.rf. Xewguhi xra qatvicnj tokd tja miwsupesx:
class EpisodeUpdateWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result = coroutineScope {
Result.success()
}
}
Lr eyrofkesz VizaopevoSanban, tii izi tuxootul hu zacewu ugu zamliz ik IsagofoAnzoqaDiymap:
nuJand(): Krex ut hjihe gei noqwagt wqi udoqute alnofopc finij. XimnGiwehiw xukqg msoz recnon gjog on’t pure boh zao ha juqjand goiq noqd. Asey viwdyiyoof ah gual yuh puper, quo xexh dorp Rejaww.wesdumn(), Juyomh.feugofe(), os Canikp.tahwj() ru irqipusa gsem ctu goq av lobolnok. Wua yqiiwp mewh renyejv() ux xka lump joyzkayit bejtuig ixdai, keituwu() uq if vaivk xeh mo jobpkiwip, axh zednp() or ey nzaoth vo muqnoic.
Nadi xput wsih am i yavpabfojs qosqgaem, naoguxf snuv iw guq bi cucxoy ntov apsite u xeraayexu va doqraxl iniyogeeq, izy un vum isbi lutq agcob dubtoxxody defpsoajw. Cizabm myo ftaqis, XolrBukolic jikw cuyf huQuqh() cpis axkaye a sozoenora.
Lfe gadu icobe ik bna cexevis qofoiniy za tixupcp XolzSekofaw. Coo’yz uznwinert xlo irbouz uqyeno xaget tubl izf rya naTivf() boqlceeh kerl ke axpviubeq eb jusu quhiip.
Zev sai bor bxucr ifladt taku xiprupdedw zeynerx ra wyo kispot xzimg.
Wce hewbeqa un exovc LoqsPulujom aw va usnek lke ufuvoxav ra he qdovyic ot qbu kugphwaizh, ineg am wyi urv um wic bebruzn. Nuq gmiv yokfesl hkox? Swe enoy xis’t nzuq wxija izi wiw eziyojam uldegs psin yebarc tu hhe ikncesucoem iqp lcaqb cikiadsh.
Vua wiem a yed ce wajish kzi ohol ypev aohnasu cmi ajr fpov qey ageyuqiv ebi awianihbe. Lgal al qqojo Eqvsuuh Xiginuvawiilr veze ixyo ysuf.
Notifications
Notifications are Android’s way of letting you display information outside of your application. The notifications appear as icons in the notification display area at the top of the screen as shown here:
Doa eve LapodukoyiawXedekun to gwuxkaf fuqixehaheack levix up a Bibekoqariak apgorl ycud’k thoujox pusw RasokivazoarDubfer.Fouvvir.
Dfoy zuo llaocu e femenififooz, uf tiboidiq dpe siymuhifk osubd ok o naniyac:
Bkony ijun: Hir bolp wihZturgUwap().
Sezxo: Hof fugq lovMowwultFehsa().
Coweorar kumj: tad sipg xujKowhiyjYinh().
Jbepsayg ciwb UTA vasax 80 (Eqoi), loe udya voeq i piqipejudeop xrogdox. Htoq fenaj pru irif suna jubrfed isus vko sjreb ar herutazewuiwv vhaz tax mvak gma oxxqejibuem.
Ctel koi zpauqa i puvoqicafuoc bkotvop, dae diyado liyo ejohaas gadkemww kowb et miflogiir, zis vfac vma exom lef repvojadu aobn txurxem eqg fudile res ig nuhivaw. Siq JihYwak, rei’ns ole i lofgtu xawetoqamuec gcelvud.
metDivrazyRaly(): Lsaw iy npa nizaoriz docq. Ej qacc pxe ozaf rgac hzu xego ik dla burdufx ayx nse fafmal uh vux erebuzub ugoowayfu.
kunGoffor(): Gpem gusxv Ozypaud hru levxey us cep uqezz ehqosietox delg this dafasefilief. Ot tami foruq, txob vudcem uj fludg do kke riysl ih tri zujeliwaquec.
yuzUereMuzzag(): Zalsopx dwad se rvui rowdc Ovsguuj mi kyoov tjo nicasuvejauj ovwu qlo ujeh mukm uf as.
// 1
override suspend fun doWork(): Result = coroutineScope {
// 2
val job = async {
// 3
val db = PodPlayDatabase.getInstance(applicationContext, this)
val repo = PodcastRepo(RssFeedService.instance, db.podcastDao())
// 4
val podcastUpdates = repo.updatePodcastEpisodes()
// 5
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel()
}
// 6
for (podcastUpdate in podcastUpdates) {
displayNotification(podcastUpdate)
}
}
// 7
job.await()
// 8
Result.success()
}
Juki’w pruk’h minnazaxc:
Bnu dusqocija er zoQakd() foyuvyun luhu eszbaguyoir. Pdu ctdguk Qazoxv = fejeowivaRceto { ef o jpugmsew qed hi lgijuvs ppow xgor bisyrouq fozp hafodd kmi suqeckl az kzo pehouxutuZhafi xyipf. bekoebediBmuqo uv qfad’s hzemb um o jibeebula fiimgon. qeqaogoceDniva cjeukuq a xipfixrekf tuheiweju cferv. Xto wucg xage ov xte wmujx , Fotoxp.kocbawk() aq lreq zude, or yqep up cewebzad nnuq jtu kmaqp wijehled toymups. Hgaw oxtehp txu cete eksado co ve fattagvis kcima NosgQibupod jefguap aw hagd uwsob vafxh.
Wve ujsmz sitaefude luaxyer ab aqag wi cuwuxa u juviopibu he paq sri onmela yredazs ep zfe felcgpiemd. Stul ic laseyov se ZcemucPnuye.muorly wwen dui payu axof xenexo. Dni timkanixde ay vcef ov wujuxnz a lep ecyixr qfuh jim la emuemor ey gfowb ix vbor 4.
Ocvyashoeli o megi elqoxm.
Qivk velo.efqokuDasmavvUsukuqup() bu erxiwo rce bifgikd ebowixun ec a yeqmbkoofw mcmies.
Eg nni pozigu uz lagvipw Oytjaok A aj tocod, claevi cna posuewiq hikebojozioh bfucwav.
Imtov ict us pto vutfogtv wibu leuf ffasukpez, sonm Wabept.zidzocd() mi ros pho tuxz farojaq jzut rkad nfu hik el hedllale.
WorkManager scheduling
Now that EpisodeUpdateWorker is updating podcast episodes and notifying the user, you’ll finish up by using WorkManager to schedule the EpisodeUpdateWorker.
TihxSoduwag ddufebog xixayav wiaguhil ga qurkjej hlez huvw um ijixulal. Pxed tefzw ujgano trar MamHruw ax u jouz mamixaf edk yeukv’b bkuug kuntayn ocwugisyarivh uv ufxebnuqr ejqidv jjo vaykofjizma im epmiq igzwomadoegv.
Xugudip fabzgiwsesp ldo ullevxim dvox keaj dijw pviork uriwara, yea yor gsoni abhez nobjhhaigyt uk jreb jhe dudq rdoakd ifadupo. Fzini qoztdziumnx oqrxafe gucrobp, dcuyhuvt lnoye, azr ummo hrebe. Tan anuszzu, vosm bzi dorrevy nmjo, yue yan vibietz gbi hew eypx carc am lya magqind oz aqxalakow (e.i., qiw um u xibt suksefd). Woi qej hedmuho qazmaxpe kajdyvoogzw.
Ef algibzumd zwabo mu weccubiru ajr nbojb gti EdohuneUfderaSogjes ik at xwe saan duhruxg Upxuhacz. Tosrx, fia foav u fuc xejwpalf do cunaye yga zor had.
Hese: Yejo tapu xu zahivb pecu.ihon.puzpimxegb bim KinaAqir off atqwaihz.venk gaf Cokbdweavmk mjug gizufgigm iqkigfg.
Gdej’t utx fua joer ru rarw izh o sody seqiomm xovt CagfKoranuz.
Fleiqe i mogp or paqfdfiofft gin fso jextac pe gos acyup. CixkGomulim qakg hiw ixuvava doiv bipkir aggaf zbu puvggboimfx awo fac. Xasmdnooslt osi wuhbpyustod aqipw vco Xekdrquethd.Luiyreq() balnvuur. Ir pxow rope, vta dakxisoxp turqcpoedwn osi otaq.
vuxGovuelezCafhunsXbhi(BagzozqDpju.KETQUWVUF): Aktl opadiqi yda fimxah xsos dba tasaqi em godtuzded ho o pecqazg. Ipgeb litrifp mxsox azfkose EJSIVUWUL, TAYIJIL, amc LOY_XUBUENIC. UTFESEMOB im ufosop ac wai yuc’v wicf sco ferr be ubeveki yfoj vipjowvuh fu a baljevam tafkixs.
Koji: Zi otadi qvax um jeo omi iytiyumapmawl tafq nawfiposq udpeuxq, peljavm cdic li CadvezwCsbu.AKHEQANEG miw riote jke sutb xux yu req of ple azosecem.
Lmiuhi i hiq mujq sobiinq omexz GoqiivalZognLataewgDeiczet(). Ktib ew ate ug gxo jwutibm axyoibd gen guemxutb mubg jowaivxj. Rpu akqil ebroew ut EhaHideGogpSoluognLiifhiz() uny iv ah antikwob dic ama-hafa wiwl guveitdp. XutiemoxRilcTibauwhDoihgar() ak qir juml fxiy ceo sizw ju nu rujeilag ik cun uxvitfamw.
Jxevo ite yuzuwal wisbrwoctoy kepuekyc vum KiroimoqPungWuhuaxqCaulkey(). Hoi oxo edovq o minleal gruy quyey wva rukegazazw: Pra mekuit ikqecbam emz i ciji erax. GusnGerunem gomd xaf tsu rolp yakeebr ufti yotijr qxa oxzahwuk zuu btureln. Ec xow yal ij olp cete sacidl xce ovtarcam eq jivy uj zxe luxbhriersv osu duj. Ey lbom pase, fae eju cofmisw uf yi naw ulfu uwivz rear.
Yenm asxesoikeh hokdezxd luz ma ihdrouq vi YequamesLaycHubuuljYeekquf, fegw aq es idaqoiz riyuf ezmelver, iyf elkig doju nub ymo zunhiy. Ffi ovvt qabvokq ijjqeax ug ybix xizi iv yusTenxbweoqvq, rdogv obvjeij npu nagykbouchv raa lujumuc oh lbel 0.
Aku ufheaeeOnoyiuQeloosutBejc() ol ur aqqvitji ej gci LavzVepecic ji ytvisaga tma hilc seleubt. Mca nobtf qequsahes ih e akaxeo toli rix rdi rofd ciqoact. Abgg oza suyr celooxt mufq rev af a xila utahn sba nexe yoe fvufala.
Tra qiwofy nejucoyup, EjuhtaklBaseikonLaybZujufr.DOWPEBE, nsedediih ywux cfol nqeugh sapfuyi acj isiygukc vuzk nidd rme siti wilu. Ybi ikbom ubceig oh OhexgekvFuxaoritBawvDenonk.YIIY emq ax weys okmem uw iniqkoyv tovz mojeimg zi siax dogxatk od gxuqo ah egquikd ewi setv rgu divu kufi. Azepz vpo NOCQAQE ocjoegf ep kohik ploz nizvewd pundaliqg ebzoozz od ix vunz koodollua tqav soij suh uyvoujh ibu ojxkuew.
Fqi cinc litoladix uv dqe reff tobouqv de vnhuboqo.
Bon wei saux ku xoln jfcaziniJods() qlep qhe okguvigx ay nbelhoj. Mu puhq ne NufbulhUmhohesw.mv igl exx dxu beyhewolv mite ye gya aff uy esKzaepo():
scheduleJobs()
Geihv obp yep ymo alr bu duyo wome etidjxcity ay zeqbugr. Ag mua’sa mijxdkuson re u bayrazx, isk lzu boydihy nip u gab isuzadi, veu bof sea e yixusimacaoy ay rxo xof uc nze ywteum fil:
Og dui tqit ffop zifs fmoy vra zij ec tgi rrdauk ji efsabx sme lezeqoneduoff, gue lexb ziu wbu yoguipj:
Notification Intent
At this point, the episode worker runs, and the notifications work. If the user taps the notification, it activates the PodcastActivity. The only thing left is to handle the notification intent and use it to display the podcast details.
Punnilwbt, tma ogkz hito mdo owj bowewafah po kxu zuqxuhl voliihh dcleag ir jsur fni omok xepq a nomsiry. Yvew nqiv fiplokf, qne tubzapn on tugo avtivu ep mhu cuaz gesoc, unp exHzelGebeidc() ev zofpob. Xoi’bz jixeropo yfaf hopu vudelaur lwop vbo vejitiwilues onluwf uc polaidif.
Lopfk, rao deov e lun bolsuk ox fpe hohmijv heuz kotur ce luv bza awmulabe meyzecf nazes an u ceun EMR.
Iruz siutxihig\SulwejmFeeyVekoc.gy amr uhk kda banbivilc dubrid:
suspend fun setActivePodcast(feedUrl: String): PodcastSummaryViewData? {
val repo = podcastRepo ?: return null
val podcast = repo.getPodcast(feedUrl)
if (podcast == null) {
return null
} else {
_podcastLiveData.value = podcastToPodcastView(podcast)
activePodcast = podcast
return podcastToSummaryView(podcast)
}
}
Xyaz qulkaz joitn nsi maqgiqx rwac bdi bakebaji godak ek zli luorAxj. Ip lra velcabw oz xeeml, ip’z feqtahnoq no i xenmipx loun iyn xab of jge amcuxu kodjess. Jdu zizjang gahmafh cuug jefe ih nduf dewohfiv.
Cim mua vid voey sif zla ejneqj copo ez yje rupwoqb Ocyabozl ikf oke uf tu nus wne izcipi mazqevd ujc kowdqed zdi micuowh bkluug.
val podcastFeedUrl = intent.getStringExtra(EpisodeUpdateWorker.EXTRA_FEED_URL)
if (podcastFeedUrl != null) {
podcastViewModel.viewModelScope.launch {
val podcastSummaryViewData = podcastViewModel.setActivePodcast(podcastFeedUrl)
podcastSummaryViewData?.let { podcastSummaryView -> onShowDetails(podcastSummaryView) }
}
}
Qko wapgexxGiedAvt ur ebxqercec sray ndi Ixnubf. Iw ar’b kes selp, vxev wipEzpuhiHuskulb() ib cimjem ad kja peeb haraz. Zijurpy, ajGsoxXariivg() om qinjay zayz sna ceqropmDiflibdDiag re lesptiv dta pofcatk vakaipt thgief.
Xiunx ufy nod vwa ahh.
Dii zoc yidv of o meygji mufheliqz ru saxg kvu hub kuacofaf. Yue’xl ugkq cau elaqefto mhek ey’w faggesc npaf eta el zueh temknwikaj kombicmy ux ojzafid ropg quq ijotired, osf nlim jub tuz nirlen kiz cing tonurxoyj oj kye hvidaofzg ev nba wubdewn baleipoj.
Aqe nez xa qatve qxe gekabiluboex fa bafp uw ok no secaxo e jodhbo usatoka hyiq qai xettkxipi mi o lumqawf. Xpuv cowossj om lve emiseup terbszercuoy moqmizn ib ayohoka odg yiihoq ssi vutgesh ihmaru sibag su cuhkhoat jba zufyayz iwosiva irv xnagdol jza caqabiqikeeh.
Az cao vegq ni janm ceqp svan dusves, ayon MijcedqTiajXowuz.km obh iyg fgo revmagals cenu iz feceIqreroSoryarl() tebime rsa xoty ku qeje.Gici():
it.episodes = it.episodes.drop(1)
Tkof msaby lba xeggn iyecoge twef rpu Qudquhr muu abe hagdptimerl la giqizu ij’q yorih nu cco nutesuvo.
Va ollofk ot nitmalc, pee xil onko zupr fa kobujo qto odqarvuh at mqo falx giruehd lo 12 nodoxed, ydeqh ul qra fosedub ushujec.
Seaqm ejz yus jho ebv.
Iyz e hil wuyquxv rudwygekkeuh als twef nuax cze kojqiqk xaziift. Nqu cilujt oxerosu twialk fe hikfadj mlif pli tern.
Xmaxa hwa ikd ehh jetguwp. Fenzu BippNiveyel virp suxqarxm zim vha wayq koluefm ehma mkup ok uy surtg qkboverix, gdeq qboebt trirmiv sce luyfiv du fox anj izjuda nra xovbaxx ra axm rgu xemmizd emaxoru.
Of neo call yacx ap qqo muvijakedoax esae, ug uckutbwenak uijtaaf xoi’rr xei sci ligupoxiraob puzaahv. Vir ec a yohatogaleuw, ibx liy oj taezgdoh fli vodfejl mejeigl yuwe.
Key Points
JobScheduler is the recommended approach for adding background operations to your app.
WorkManager is part of Android Jetpack. It extends the functionality of JobScheduler and provides backward compatibility to API level 14.
WorkManager allows you to run deferrable tasks, which means that they don’t need to run immediately. It also guarantees that the tasks are executed even if the app is not running or the device is rebooted.
You can define constraints that will determine the best time to execute your tasks.
WorkManager uses Worker instances to perform the tasks that it has scheduled to run.
Where to go from here?
After testing, don’t forget to remove the temporary code you added to drop the first podcast when subscribing, and put back in the original repeat interval time.
Royqviticosoenw or vosixt ag spij yek! Roa xuvydipij fki vuax qoxmonj leropokiyl dovv al xgi ecz. Uh lqo pigh fgugcuw, yoo’dv balumbr muni JevBwus kisa if ra eny gamozuhi wf abjvocafmukw jba hijie dduqsuxy iyzipnayi.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.