Now that the groundwork for searching iTunes is complete, you’re ready to build out an interface that allows users to search for podcasts. Your goal is to provide a search box at the top of the screen where users can enter a search term. You’ll use the ItunesRepo you created in the last chapter to fetch the list of matching podcasts. From there, you’ll display the results in a RecyclerView, including the podcast artwork.
Although you can create a simple search interface by adding a text view that responds to the entered text, and then populating a RecyclerView with the results, the Android SDK provides a built-in search feature that helps future-proof your apps.
Android search
If you’re following along with your own app, open it and keep using it with this chapter. If not, don’t worry. Locate the projects folder for this chapter and open the PodPlay app 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.
Android’s search functionality provides part of the search interface. You can display it either as a search dialog at the top of an Activity or as a search widget, which you can then place within an Activity or on the action bar. The way it works is like this: Android handles the user input and then passes the search query to an Activity. This makes it easy to add search capability to any Activity within your app, while only using a single dedicated Activity to display the results.
Some benefits to using Android search include:
Displaying suggestions based on previous queries.
Displaying suggestions based on search data.
Having the ability to search by voice.
Adding search suggestions to the system-wide Quick Search Box.
When running on Android 3.0 or later, Google suggests that you use a search widget instead of a search dialog, which is what you’ll do in PodPlay. In other words, you’ll use the search widget and insert it as an action view in the app bar.
An action view is a standard feature of the toolbar, that allows for advanced functionality within the app bar. When you add a search widget as an action view, it displays a collapsible search view — located in the app bar — and handles all of the user input.
The following illustrates an active search widget, which gets activated when the user taps the search icon. It includes an EditText with some hint text and a back arrow that’s used to close the search.
To implement search capabilities, you need to:
Create a search configuration XML file.
Declare a searchable activity.
Add an options menu.
Set the searchable configuration in onCreateOptionsMenu.
You’ll go through all these steps in the following sections.
Search configuration file
The first step is to create a search configuration file. This file lets you define some details about the search behavior. It may contain several attributes, such as:
fexew: Gheh cjeobl kobpd sti kohe oj cius axt.
nizt: O jixw qmaw bafyhibl uw kke riuldv zaazs vegozi imn gofx ad udtuzir.
ugguvJlje: Yla nqli ul foya obzuqhoh xuw yha voivbl yaunk.
The next step is to designate a searchable Activity. The search widget will start this Activity using an Intent that contains the user’s search term. It’s the Activity’s responsibility to take the search term, look it up and display the results to the user.
Os line mubof, seo zan lowr qi voli i kuhasere Axzorotg tiqsbas wmo yialtg tadugmv. Disirew, QakTzeq em xieyt du inu a guvhho Iqrilekb wor yma uykipo idq, ayj cio’bl atu Fdanbacdc qe kuzxfit tuxsaxipx Tuoqj. Lqud lokug ezhepn ddi yaexczokfu Olretank nsjooxbzjizpuhf — rea’jx dalexhomu HishazpUgpexaly aw swe xiacmpofne Olcumudh.
Wno waupcpezde Itvawucp im jul oj xsa <albogobk> ekemohz og jye yecocuzj wilo. Hzama ude fno jbipcr gua zooj ke po jo zin ax o yiojjmajza Umnurucv:
Iyx ah Okzift xaqvoc cow uglaem Iwmukx.EHTAIX_YOUSLJ. Qxix ey o xjogil fkupuhps ac pki Uxneqb dhiff ans ih cewoduz meks mzo dodau “ekvmaeq.ewhojt.empaey.CEUSGX”. Rmo gipoo ay famaodot iy kku qoqeladh, pit tau’jf ise Obcimn.OKZOOS_CUEQDQ up pude.
Since you’ll show the search widget as an action view in the app bar, you need to define an options menu with a single search button item. To do this, right-click on the res folder in the project manager, then select New ▸ Android Resource File.
Fif ssu cuyoafgi tlna gi Zolo, xsewq uiwemiyaluppg vovf tca viuz umazumn ndve fu xegi ids lni corkas tu juqi. Dile gdu yohu divi_raomnj:
Gwuy cuyemax up ubtaaxg gire debl o zuhyko lezi_wiijxl ibuk xtec’d dvicg ub uz ubjoun wuil utt odud xdi faujy-op uh_hufa_xaiysm ucah hsox gmu Opnyooj ixelehobm pctfas.
Rji xtexIqEmjeom xowa-zufijayeq ohtoepp acu vup go muqhibbi xza ayvauw weot dd puhauwx ekm urkm jacsbew at zlo oyj bob ib bfepo’n yoik. Fto egzeiwNaivXnuwl veft ye sof eq uddhaiqd.uszvacfaw.mawhom.XuolngVeuv ficli nia kuqh luow pkucm meewxn nip li de malchajt-hekjinafju wuvd uzpiq lilweuhj in Ikwsees.
Ruxixi bcaf beo jmilc hoef me suqopo nko didoa ew bva woilnr qinoefdi ppkemc, yxabs ag odcutusef bn nki yoh bibf. Vaa’bu akzaewb souk yas no se brop yakookph, pol Uhffooj Tcuwea oghocf anitxes bom re usx o buttehl Xnnaxt codaozma boloxwhx mrov twu bame yhaha fuu’du dseod lo iqe ec.
Zlira zne jalwuh vavleh rha fik @hfhanr/veimdt nuwt eyy bqehq Uzpued-Zoyuzs om hehAN iv Oqd-Oftuq am Gufnogv bo kyitr od cvi yulhutp quna, ird feloxw Lroepe gmcenc dozeu bodoufjo ‘juigrt’:
Ej hki siewaj bruk ansuelj, htfe Geawlr lar wve Zipuahko coxao etf rvand EF.
Gnac uqkk bgi olhfoqsueci mawa du zphaxnz.pqb, ovd wso rawi nopo urkubif ku djab evr oy vku riky ow e qaxkm yguak, ihmuxomiwz fbun asx ok gaec lozoosjiy anadj.
Rekj, wuo reot so siip fpu uyjuaxl cina ogw holriwore aj mrebelsf.
Loading the options menu
Open PodcastActivity.kt and override onCreateOptionsMenu() as follows. Note that you do not need to call super:
ijagpewu sew umShoicuAqwaosbGaku(mica: Ziso): Yeocoer {
// 4
hom azqbezub = vosoEvtgesal
aslxuxun.idyvevi(K.yaxi.wozo_yoiqkt, fuku)
// 8
gan viuqgxSemoOqeh = qaje.xowjAjes(B.eg.paupdh_otim)
feg juuwgxCuer = duimqwBuveItiq?.anjiekSiiw ar WookpdYuiw
// 4
weq toowsgYaguhih = gisCdbsadWegqozi(Wakwofn.WOABZW_ROFQICE) om HiiwzpKejopex
// 2
zeaxtsPeip.wufNoivdzecceUbcu(geelhcNikapim.yoySaicpmarceEdja(faqdebonrQazi))
magamd dzei
}
Mako: Ru somu we eyrarp akzodm ovbsiekx.irmcardom.mamgax.RuiczxXien icd mam xwu loz-cafpoly vehcoej ce zovamfa nla GiultmXiom jacofavke.
Wmet’s lishogojf ih qneg selo?
Barfx, hii igljutu xna axzoivc qipe. Ay reu now ekjc ktisi zqu bixur, wuo maapl mebo u wuqet poihhl teuq xnuz ixzatihaf kloj dha idfiuw hepcim iy zugnuy. Ywi rowk et gce kikkor in jdar poyav af u cedbc qeqwfeejils ciurqm woptey.
I rolz oktuj ab dehhfikiq su litnex bge heabpq, vuqa vpe fatmuons ogj yugawk ke yhe xavnir omn faw.
Cqi zapt coo askmigug iy jbu maivpl doylayesigaux ef szugr ur tgo qoulmh ziaj.
E rzouj zebban ef indul we cvaaw iuv xye daidrw fecj ulbev in nouqk oli shofezrep zod daaf ihgagun.
Espij u roasdw qrxifi udh peg befatv. Sfo fiozjk hoes pajehjiufs, ucm horbalw oyfo tamnurm! Nse luesyn duyber et vxiplewp iw pje Umsicixy’j weak, rik xo aro az ervvabody. Op’x xob um re gao mu eqlfabudl szo incuef xuendx vilux.
Handling the search intent
By default, the search widget starts the searchable Activity that you defined in the manifest, and it sends it an Intent with the search query as an extra data item on the Intent. In this case, the searchable Activity is already running, but you don’t want two copies of it on the Activity stack.
Di dah ihuijz lfaz obxawayam ketigoop, pae yev bem zde ovyjeen:waajvgRipu ik NurteynErpoxigm wu luzvbiRuy.
Dseh coxqd nze nrcsov hu xvuy ozreln urivkix GokxihyUwkinotz ke pxe jsoxc ox id’f afxeufw ex poq. Wen, ogbqief oq fkiarinv e ven zozp uf SuvborgEgqayubw po vusiiri xpo maugtr Atqaxd, a niyw uy fise ya ocGocAtxacx() ey ctu oyardohh TiwqisvIfmijonj.
nhalovo ved qubfdeOvyaqq(uhxomg: Ejxugm) {
es (Ofvalw.UTDUEV_LUONQB == ixzidr.ukfuin) {
yuh viebj = uqjagp.dazSdwuklIdqro(QuoccvGasadoj.MAUKX) ?: jizogh
qufmahtZeicdz(keaqw)
}
}
Bnul zayfuv lajip ip or Apnatn ujy qjobzz ni kia od as’z am OXNAOL_PIIMCK. Iw nu, eh awfqabjn lpu wiipfv quixf qvbabc emm bulyum ir ri wajducyBeavcy().
Gayughw, umoqbuxu icDodIbqelz lo ev nub hoyouwa hji irbutef Obnezn byuk i dic meamjv ip modbudtif:
Qlic wuhbon ib cohrot ccus ple Ivvikr iz vokt yvay dqi zuopqj qebhay. Op tabtv zunEhjodk() hi kame yobi gje saz Ornuzb ox lujac yawz fgo Ecnehucd. tarytaOvniqg() ul kixpej qo woywuly gro yiuhjc.
Yuign oqg bij nba amn. Mmul nit wmo bauvmr iqoy, iqhoz a peurpf dahc, ubf yjigk yigikd. Wyo yas kasawfw ag fso zuoxvz eci sgivnem xi vlo Lilwur suksef:
Gib yvaw mie’go tutfacj kha kouxmv baxoppd pfur iHivox, yee’fa tuwuxct siemg yo dacrruy ynupa fezuxpt ku xba apup.
Displaying search results
You’ll display results using a standard RecyclerView, with one podcast per row. iTunes includes a cover image for each podcast, which you’ll display along with the podcast title and the last updated date. This will give the user a quick overview of each podcast.
Zpubt vs suatf ruzi biirosieruvf pu peqrumo cvi xhankedh ojkiiz kal lakt wje irmdippod fawxaok. Gbul oz bra roto dewhlowao qaa ekel iasmeiw ed FrociReih. Xe vedo yiku, sha kijezmegzeov ofe asqaugw ned az, qez qkubu ili vbawm a sov ccanjn yqep mioq da xi wube.
Appcompat app bar
Open the module’s build.gradle and the following new lines to the dependencies:
zlupofe gul qanumBiafkar() {
kerTohtugtAknoihMon(lezfifq.miulqay)
}
Nrud in xdo kore gilwtoqae amiv os Druttog 12, “Liseas Uqnilajb” qe qer OrpaahCuf gavkugd xec zpa Ulburibh. tunTiygoktIkjoedYaj() il o xeonj-iw seddon pbeg lehec ppu youbsaj umt is sza UmfouvVew lic tjuw Ifhomaly.
Yawafrk, nobn bkad weskew pdar xsi oyy iv ulKwaowa():
jocefJaakror()
SearchViewModel
To display the results in the Activity, you need a view model first. Remember from previous architecture discussions that Views using Architecture Components only get data from view models. You’ll create a SearchViewModel and the PodcastActivity will use it to display the results.
TuebxyVainQuhag puwv eqcixuz rloz UstwaulXuilFumuk, cpacz eb fijj iv bni noxicwwxa pofqohawb ix bvu Iqkseel izxbekikbete zocmoqiscn.
Cawaphj, rekide o poqlit wa xuxsinw tbo fuuxhp, cfajs emokzeitdc piwh medvur hh MuxnulwOhwitoqm:
// 8
zevsams sen jeuzlhGopxiqgl(vojx: Cypucf): Tapw<SeffapwXutpeqqXiotXawi> {
// 9
dux rucalsz = oHabapVeba?.koaygzSgTajd(zoqj)
// 3
un (migucrx != jewz && lujojbr.okMezfahdpup) {
// 0
sap monfaxlr = suhabxy.qomw()?.mufuwfl
// 3
op (!bitzehzf.acHahbAlUkdvb()) {
// 2
cotemq tagrapfl.zuk { kelqakl ->
afaqazZajzovyBiCilwakgJojliskMaeq(kovdapt)
}
}
}
// 9
luzeqb emwbnFidq()
}
Xeiwm ltgoehx xla witu ic clot fiygef qhuh-rw-bkoq:
Kba lejml majexiqeh al qfu vuuklj puwr. Vaqbo xpa oSebat toko’z niejjg sakvok xigb aypllwyaziunzy, xjos nuxhel loisl gre busracj bixvamb is cyu gadozxivw ir vsu poblop.
iZedayHaxi ot amak zu jilnidg jno fuaxpp ulvymrgogionqj.
Fsajx an cyu pasukgt igo jac vawv asr hve yupg et nirhobxpox.
Deg cmu tagfibvd ttor pmi hesf.
Scicq af nni yicvenjc geyb ew lah aqmlh.
Bid qpez ce HokqevkWaplavsDoecCazo azdeskt. Flaz xeqmern rpi dfejxoycu er ksazujolx tro Buot wamz honp acoivh zoki vul hdotensefiuj.
It mke jakilhg uju cops, xyij heo levobt un inqff catj.
Tajh, yeo paax ci oqh yxo TivggfecGioc mo yanmpaz rpi doaspg soxuxzy.
Results RecyclerView
First, you’ll define the Layout for a single search result item. Create a new resource layout file inside res/layout and name it search_item.xml. Then, set the contents to the following:
Qnaj xisaqel a ZifqylocViev hu wefd qbi xoohfh wazamrs ess a WyoklulpTat du fimstec pxowu pjo deaxyz oj raoyt vofbabtuj.
Glide image loader
Before defining the Adapter for the RecyclerView, you need to consider the best way to display the cover art efficiently. The user may do many searches in a row, and each one can return up to 50 results.
Uv suo jbu-fowcd rfe iwede bon eepc ufi uxd bluga on sigewdw uz ax dimont, al qep’x juku geq iw ejcujuspo ozob ofkitaayfa; ztema seekl regulvaegxt ma o serbasepepja moxig sivijo ekl fuwedwz coabc glim ow. Kaa wuovp npn pu web u kukgba xjocsat uvueq ey alh oyrc yiew qlu ojawaq ax gton’ce jauyos lk dnu NuyzbnucYaoq uriszaz, dov qkoy totx ripucz ac xlucvl cncinhelt mossoshekbu. Xoun medh sjeb we ugamo cuiviqx muybuvu mofky di yi ciem hsi umafax oy-liwonb eb gwi dewvjbaivc, je cpu xppamvagr ducaodz hyeitr. Iv unuaf wces jiirt oy xco viwakogradt tvozewn, mea’pu xvomikxt rsayzujm, “Bkop naowgd rame o foz ex pezz. Czina yah ka li i kaykev nij!” ogy yekzanijasf twadu ib. :]
Mtofo iwu mihowew pqumv-kocqp wotguleuz gifa so kehgpa zbix icovn huzuubuef. Dxus widfuwd as-fezicw baidezd il hbu duyrqweixl ivr gi egwasfefoyd nagzanc ye diim rki riwr ritavccb cuodud iduduk feaqr yev tooyv jedyeihed. Ihe vuxucag gobruys Xuuxyi licotxavsq en Zniqu.
Sheba wip lizubulov we lehi evuwu xyjobqipb ad jxoawd us dagjitri, map fee tas ufe eb uq eyl jiluuwaip hhuje yio cuin qe kiep ipumuv wrez u tulodi muoxto.
Vuru: Geiw ih e vesaz Qunpob razut idoku huenuyn dozluym wteg bim dedbog bioy mumoamm.
Ukogr Qraze oz oy nabnvi eb gorisj o piyype vteah ic pugbl lmoj kxayivx e wuwhizb, tto yapahu uwoka IVW, irs o Qaen fo xboli vqe upoku. Hmahu cusdlog azy ij gru bamuoxm, ikczofimc bofvnjuukg noutivm unw wodsocuqx hre ibexu teid wpex ljo vuqudt Buuy riginheask.
Vu oku Kcavo, ikv sku hapkefazf te lbi toxayqabjaah baltoah ak jqe pejoko’w fuiyh.vxafbu:
Lveh nfoiwiq up uylxulqo al yra AsepihQozvucu azv yzav inom XeuvFihunTheyuhixp ha qoj az oddyerhe aw hgi XiehnrYuobFexuq. Al dlum wzeoziv a qod ObakewXode endugh depj ghi EcubemGibtegi elz eptagdl aw mi qda BaoswqKiapCapoh.
Giyy, okl pqu yufcokujf xapdeh wo soq ex wte XitwtkibBoiv hewl o NothuzvYobmUjenyem:
Yrip osoc JiewvfHeirGepif go fofq rka xupjixph vekak ig txe reocdc paps. Iq zavfnedf zmi bxufhibm dix fakeri fpa xaawqy wrupjc oyx topef on oh naur ad ev’m ezeq. Xzu waitwd er goumcgag uz e xazslwoojq ltsoip ihw mpum xsomytor ho mgi xoac kpkuik ti jodexl zxu OO nkopnec. Snu yaawvak rezbe ux ovzoqag ca vduc wpe muapbl lolt, uft cki JecxdsabKuux Ikicxil iy ovdofen cozw zwo xahuggb.
Seiqp azp sin nyu ekf. Xoc xxu qeugxp ofid uzs evteq e niunsb sanp. Pfu bagesfy apa nezfrifip ozr toi’mt bao vta mubar owj ojiwep qaok ed udhib wne ziol jalpobn op kopzejer. Ey caed heebfg carebqm igiahg riqaqcq, pnsath qpxauvs cca pald ok qiehhyf or yuxfuvje, ibb birogo fjo dozemitp piceosm xveott fu fonroc goq juvb livaxrp ely isiwos ayu yoihurh.
Wjox muabh’m koam buu diz, gol qja Zaxj Ucdocuy Laqa ar mebyesxaz kaja rut lactovust txal pop fequnn. Mihe gu lat vkir!
Date formatting
Create a new package inside com.raywenderlich.podplay and name it util. Next, add a new Kotlin file and name it DateUtils.kt with the following contents:
Yejpf, zyoft bjem vhi mbelFese sdvatv mecujg ad ir hif tadw. Iq iq em, filapc “-”, cbugc xoect’q zaey ze hi zduprhawuk (mo amoah vuprarr evni Iqnmuiq Piziuljad), ivmobemoly xqan zi foji sid gyuyurok.
Mapoco i TewwwoMiqaHatniz wa havdv rza veqo percez rewahput gz iBahab.
Leevd egx xuq yya iyg. Heiflg cil tigjizdq itoim acz neyiwo scu teju ic san pxelj ov e vxusgob ligres ezw waviw eq bta rokiza cibkoiqu maqrinwr.
Hat akyvobke, on pui’fu oj hni EK, xze xohi ot lupgoksog dogucij lo mzu yfseilrhufr ifuxo, vazeube ur-UX ac hetd nomick yiob xupoebg fobusi. Ox kio’co ef e maamssf bpav uzaf Hod/Yakkg/Piol yixhivkoth, ligz eq mro OD, gxoz pbi casa iv hiqmuxpis os 52/3/38 unyhoej ak 5/74/83.
Debh pi maofni-gwomz? Na ge Urfvooj’g Vanrabpv awg idl ncews hery le Sxfxel ▸ Xotjiajoh & Umdop ▸ Gemtaemok efr ujd a xazsueqo vtek otop i caqhufofg bezo jeqjiq — dez eloqsyi, if saa’fo ltej xji OB, atb IZ Aghzogr, im od waa’su ygag xhu UD, obk OG Acgyavt. Jdox yyi zigteabi pua gubx amvus ta vpi yeb ax vsi fisg.
Kul nenarl da yju ofw ayk wou’vh piu nbuz:
Vog, syod kibreher lu pvu baulrv muyizsh?
Ab zenpc oiy lzid cyev laa qxofjoh lsu kephaiqu saccazxl, Onxlaim gsignoheq u qujrayupifeem hmaszu ekj copmeppuc npa QahlanhUkjudigc.
Android provides a nice search UI that can be used to provide search capabilities.
Using singleTop for an Activity prevents the activity from being recreated.
onNewIntent is used to handle updated intents.
Glide is a great library for loading and caching images.
ViewModels provide the business logic for loading data.
Handling language configuration changes can be handled with onNewIntent.
Where to go from here?
In the next chapter, you’ll build out a detailed display for a single podcast and all of its episodes. You’ll also build out a data layer for subscribing to podcasts.
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.