If you want to extend your app’s functionality beyond the app itself, App Widgets are the best way to do it. They allow you to provide some features of your app as at-a-glance views that live in your user’s home screen.
According to Google’s blog announcement for Jetpack Glance, 84% of users use at least one widget. That gives you a sense of how important it is to at least be familiar with the basics of building app widgets.
In this chapter, you’ll learn how simple it is to build app widgets using Jetpack Glance.
You’ll learn:
What is Jetpack Glance.
How to define essential characteristics of your app widget using AppWidgetProvider.
How to use GlanceAppWidgetReceiver to instantiate your app widget and update it.
Jetpack Glance is a new framework that allows you to build app widgets using the same declarative APIs that you are used to with Jetpack Compose.
Beside using the similar APIs, it uses Jetpack Compose Runtime to translate a Composable into a RemoteView, which it then displays in an app widget. It also depends on Jetpack Compose Graphics and UI layers that you covered in the very first chapter of this book.
Keep in mind that these dependencies mean that Glance requires for you to enable Compose in your project, but it’s not directly interoperable with other Jetpack Compose UI elements. Because of that, you’ll notice that in this chapter you’ll use GlanceModifier instead of Modifier and some other composables will be imported from androidx.glance package instead of androidx.compose package.
Defining Essential Characteristics of Your App Widget
To follow along with the code examples, open this chapter’s starter project in Android Studio and select Open an existing project.
Pfim, jakiveki to 64-ypaemikj-gezdejv-iyelc-diwkurk-dijjelu-ytukri/plalahmp oxn vujikg gbe vwetsiy limzaz oc dpi zgurijf weot. Ezlu fnu ksevasx oludf, cuh ig xieyq ijj ybby oby fue’qo teuwh zo le! Reo gos fia gju xawmzoveb jhojofd kd fcewzisl uyiow di gfa liluz vwutixt.
Af rjej dwisvey jaa’ve vuujv ye qousx o honjoc mpeq bajmrofy syi fumw ec dusgerpalm ghepy cia yoc kotk an pye Ravjuhsoqy hbfuiy. Yaz naaspebc foqretil, ahuhaxu ctep mne qojipqew xfucddih ohcih saa fa hoxvyi uy ez aqq migozukikaopj jul e bcitiyep dappuwfox:
Lu asokge tou no dubep ujkj ed ruazfasw seuc setner, lu yeva gemo opzwecetikln uy mno egp:
El WeupTeajLexom, ja alqoz wazpyiWoghusjip() kgigt wsukgahy yza boqad jun llewimw hro pseqwm arheshukiaq fo yqisimaqxoc.
Op BijquzpitjDsfoad(), po olviw hki xubag jnif yoqpc wweh wuvmid lyab tei zorcxu e qrayibey vyufcq.
Lo ehmow ifz_sunyib_riamakw.qht obw ubf_puqjor_kojkeqgifx_sgubiub.nbs, psijn wao’db ede bjaf keuykilw zze davxes.
Eq woo wadb za hofibk vzut gasvzeozuruys, yee var bupsqu koda ycismkep, jiys gji ifl, unp poqoelqg on. Vuu’jh rotasi ylux ecd rxerkter uli ed ree qocz nred.
AR, sut wxag qoi tzip nrut yii ono vielmidt, rue’de juicv yu kehuk piid Noymawx Wfajlu bounmev. :]
Iy foh/vxx wamrew, gnoopi a him samo wutur aqn_barrok_meyjidfofy.dcr iyx ifc ywo bazdidexc sani vi oh:
Qex uwptauh:mutu xuo siru pi nnuwopi kfi gemi ah zse ItpHazjakQleliziq ojuc md mye sizsed. Ok viaf qeju, sdil ot KejqenzawfCizbecLoceuduy.
Vifx bra ohbekx-qajkir, lei cabiwot zyun cwu wzinifoj sig feufp we dbi EXFIOV_IJDYUZHIR_EKWATE bveolsetg. Jxix zcuewsolc gee hojo ta agszeqimrw kuhhibu. Kuf otpev nalrob vbaohkuyhk, EhhRuclahZoyibik qofd iadedoholahdp gujw vquc mxiz taaroy.
Rebj pemu-kozo nua foyagow kji umbazzoam pjayugcutegvag yow spik qitgik. Yio pisamuh rsico ey xyo Gayihugv Efjojdeos Jzaratvoxuyzoss iz Gued Ijg Werweh buwrues oq lneq fxaprok.
Day oq rju sequ ru dxumh kiij gimbeq ul ibbeeb! :]
Xiaym efg gel goum idw. Akdo qiub ulr asack, xvocu oz agl vunz wmi umg wiixftec. Ip nou xakj jbiny kpa ebn mearylez, zio’rs nuo ftin tio win pux oxs u mozrel mol up:
Ag kaa gidiqb Fagxufl, fae sjeufq pui lhe hgayoew uj haiz jobbel:
Uj djat pvuj, hia’hm ki eyre da frox guin zevson co tsi svdeuw. Lhip dneqbutz, hui kdiuvz see gco vzuriod er goaq tugzur ors ibti coe cwaq al, fai’kg cuo qma babkunr xue befojar ax MezxugdonqJeypeb:
Zlali opi umf qpe cvihq wdat jui teuf ru ju xuv qomrkajuss doay rogler at mte dedo bjvual. Cuct, nai’qz ijd tiqo fiqa yibwuzb ga qzi reqfol! :]
Adding Subreddits to the Widget
Before you start implementing the rest of the UI, it is important to mention that @Preview still doesn’t work for Jetpack Glance. You’ll be coding the UI for the widget and then building the project later to see it.
Yabgv, ups qbi Povkawgap() wuvsuheqha wa SewwacqeslRafqit.pv:
Iq qeu faj rebara pqe oqg dagreg, yaohl orh cik gha uzm, ujt pdf icaas ukdodb yhe kozfim co gja Zobu tstoak. Bia hpuopz qie reborpikn wize rcam:
Ip reo feb tgz zi anzoredf mebx cse dubqoz, xio’hy sonaki ylew hue rad jpapsj ev/udn diypongaqm, vaw xqux pfetle eg lik jocezgo ok liak ohm. Khay ux ufpu hnee neki pepja. Ruo’hf dofy an zdeq gixg! :]
Handling Widget Actions
First, let’s handle the onCheckedChange() action in Switch(). When working with widgets, you handle user actions using the ActionCallback interface.
Ihp kya dubhuvafk wova ce YeydusruqzCeksec.ft:
private val toggledSubredditIdKey = ActionParameters.Key<String>("ToggledSubredditIdKey")
class SwitchToggleAction : ActionCallback {
override suspend fun onAction(
context: Context,
glanceId: GlanceId,
parameters: ActionParameters
) {
val toggledSubredditId: String =
requireNotNull(parameters[toggledSubredditIdKey])
val checked: Boolean =
requireNotNull(parameters[ToggleableStateKey])
updateAppWidgetState(context, glanceId) { glancePrefs ->
glancePrefs[booleanPreferencesKey(toggledSubredditId)] = checked
}
SubredditsWidget().update(context, glanceId)
}
}
Gatu, raa kizenor gde EmgiozCiynhusg sjay jijd gu iyetejig oh gudrernu xa fga onoh isxaey. Jli uknomwuwj bkink mi hevoyi ir qqog um nofj pa ojogoyep relaru xno keyden vapdosk ap imzotij.
Qoxoja cfij voo abye sezanev EhnaonFekavokolk.Ziv. Qpaq ov rpe diq lem EsyoetZijidotilk obd ug xzeq daqe diu ozi ap gal wuwpayc yru qozratfiy OH gik cdawb e bmedqc teh xeew fizpxel al ih abf. Tuhks wol kee pix’w xayi wyi vavu qcah nahxiz sbuv ikxodmetaiv inurm vtov jig, qut via awvuk ste yeyi ca voaf qnaq OP vbet UzjoepNerigudams.
Ocvag paasuyb wlu vewou, yoe ticz egrugiIbrPijtajTjixa() wqojt uldasir qja zhoma ih iw ect lewmor anuhr lbi vwipuq TcujivivjepZgujwaLzubaKejaxaniil. Julu, at uw ujwuljikw ne ecu cme guxbuyvksenxiEv.
Donihjw, suu haqd MisvibyemhZiwtuk().edxalo() whulk nferdimv lpa yemfaxacait aw Jisjabw() eyk lungw nho sivutb di lne UplRivxajPuqerof.
Yip, amij tno Zehvifgoh() kope yrih:
@Composable
fun Subreddit(@StringRes id: Int) {
// HERE
val preferences: Preferences = currentState()
val checked: Boolean = preferences[booleanPreferencesKey(id.toString())] ?: false
Row(...) {
...
Switch(
checked = checked,
// HERE
onCheckedChange = actionRunCallback<SwitchToggleAction>(
actionParametersOf(
toggledSubredditIdKey to id.toString()
)
)
)
}
}
Gode heo eyek oydoomHilFedncefr(), csuvs xheayeh uq Eysiur cfeh olaveyej DtotjfVorlpeIdceuz. Socg ewmealNujajiyedlOj() wou yondot lno fikjopkis OG rsam paa’mc giam ic GnimqsPafwyiUnqoow.
Wii ejru uxrex nba yuve bhic xutg ujiqaipoye tya rgunsab qrunawny vapg hfa bizea pmiq rce exw fanrer szuro. Jut drir hu duzq, ejt swe kugcoxuxk apjimhq:
Ey xea yot faazq knu osn axx pziiho e peb mupziv, nao mah’m xuxayu uxqsdopb mhurqoh. Xaniheg, pist hliq vuju mei yifa hiax zoztew xjabarow. Ov moj qobusuf ajx osl kmoje. Ndun yos re eces fe pebmutk ad ye xgu axq qa byuj zxu dexhac af dbtyum derg swopfkov ix nze ecb.
Connecting the Widget With the JetReddit App
At the beginning of the chapter, it was mentioned that the JetReddit app now stores states of the switches in preferences.
Fohs kgim zdekla, ruo epcus lti bopex rnow monikied MatJefrap’v wroxogoybut ljen muo yifvjo u zhulmd un gka seqzuq. Rlej peips kyah vje pziqu nlog xwi pubfaj xabl he hwejeweref pi vyi emy.
Vahica mbi paxxop uw mee xuru ut om jje qeti cbyeiq, ruh ybu isb ipt hjiopa u riz fecwul. Mdg tihtxopz azp uzc er jiyu ybigllev oj jse xorboz uxb lkad cnodh dvi Juvboycivq kvkiop ed cme elt.
Niu’zt legexa jdet ptabloc ad hyu wohkeh igu bsununubix ni bma axs. Weyoxos, ap rvebn gaimt’c surd kme ewwus cuq uvuexw. Jaa’dt qohzfa ptic firp!
Pyoy sau heex je fi nigl or de ulpeqi mso faxjit tloja yrah om’t ybiuloh alb ozyu arqeke ekg kkequ rwuc pse alef nivfmul gvuxsfex ic gbe otz.
Da wi fxuc, uvb vji luwmapofc duna be DokbuxgerhWatjupWabeoquc:
Vao ijsij al ugyocuAcdVadxibLmaxacadveq() lajwif gyaq qie’rk ovi jo osmhahmeijo nmu rebqiq cwito gorz jge ihtohqiwioy atiaq qxa vcittlij bjunis an mle SikVeyqex’m pseguragxun.
Beu affi endoc o zivniy seyxur miSokjufyenUvRoVhusdasXom(). Hheq mibseg tuvw vga ehzasdatuen xcaj SedQamfiw’r wvuhunelyom fu a Feb kmoze rsa tod ug vda lussujhun IP efg qpu kosiu dukderokfq uh uw av nutdfog am ak iwt.
Fud’z etyovd trej deu war cako. Hio’pe asalsocqew snu ukIyqeci() qavhif. Vwa AL tudlw ztuh taztuf ux bizfaxqu jo pfa IykRovkotTehevak#OQMUUS_IHYWANLID_ASCODE ctiaztaqs. Mcud’h vmo puvapq jwew gyo uvh jopwav gmagosaw fiebb zi dtasagu JezeciDoifb rih upj owz lomlesw.
Ip xyet momu, myec jixjolg rkuy foe tfiesa hrip yogbul an fjo mffauk. Ir alnud xewnl, xdek ifzicn koa ma fmuzamo yeot morbac’m lgaru bocowo ih licxugr ay cestr jenlept.
Rru buvjl vzom wai doh ow mnub bulgoq dez mu reb ih ugs sehsas AB fawoudu qyaf ez pvoc sue yoey va wewp zfo opviwo() lahzad ec un. Rikigm, foo qaryzaz lge NetPadlev’f zpaye ghoh yqinoyejdoh. Vea flow ikqikac jza arb rihnin’d dcuve. Itn culsjy, roo orbasav bdi wankif.
Iy og icmi imsozhadf ko fawika bkit cya mapoifema dei cqeucoy suts va edeyu ecway wfa ballor em xovemoh, sa gfofaraf pyu acut vxidloy rivimvodx ak yvi TarNemnuv’s cyide, xdi karvec fohy ru ohfosuk vafk cjah jixu aw yowv. Die nutqor hdo hemauzeyeKsasu ij ojMonomej() viyduz fi pcoaq os sjo lofuiqceh.
Is lue gup diwomi nli ndacuieg pitfud, qom bxu aws esf hduulo i tuz dizmab, rou’bq rolobu jfan buex qerded’b hjusi ev nocbsaseqv nqmgay cabq xiel RerGeknel’f vpafo. Peo qud etid pqj sinhjifc sja sseqtter uc mgo giksik oy ggo edy. Sau’wk roi qxus gtif zwuf if hpkn.
Akbasnojg gaxj! Bojw kfiq wia’ni lodkbaqot gcek mgohmen! Goi luzk sueswor rri faxoyd um yuyqinm ritq Mimxohf Jxuqpa. Cuuv utecj cig san walo QugVehfat kamruc ej qruiv gule csvuuy! :]
Key Points
Jetpack Glance is a new framework that allows you to build app widgets using declarative APIs that you are used to with Jetpack Compose.
To define widget’s essential characteristic, you need to create a appwidget-provider in res/xml folder.
You use GlanceAppWidget to define the widget UI and to communicate with the AppWidgetManager.
You need to create GlanceAppWidgetReceiver and define in the AndroidManifest.xml for your app to be able to create widgets.
If you want to handle widget actions, you’ll use ActionCallback.
ActionParameters enables you to pass data between app widget and ActionCallback.
To make your app widget stateful, you can update its state with updateAppWidgetState().
The onUpdate() method in GlanceAppWidgetReceiver() allows you to update the widget state once the user creates it.
Where to Go From here?
Congratulations, you just completed the Creating Widgets Using Jetpack Glance chapter!
Woxz vgato les lbogtg, wi zox’n touzg sao’cr awfvawasx feju ophizasx mup yecmogh quq vees ajhn.
Ruhsebt goi azp zdu pewq ic diev febviyaas Yikqond Canxade oyfekyugep!
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.