Before you can achieve the ultimate goal of allowing users to bookmark places, you need to let them identify existing places on the map.
In this chapter, you’ll learn how to identify when a user taps on a place and use the Google Places API to retrieve detailed information about the place.
Getting started
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 PlaceBook app inside the starter folder. If you use the starter app, don’t forget to add your google_maps_key in google_maps_api.xml. Read Chapter 13 for more details about the Google Maps key.
The first time you open the project, Android Studio takes a few minutes to set up your environment and update its dependencies.
If you’re following along with your own app, you’ll also need to copy default_photo.png from src/main/res/drawable-xxx, which is included with the starter project, into your project:
Make sure to copy the files from all of the drawable folders (hdpi,mdpi,xhdpi,xxhdpi).
Before using the Google Places API, you need to take care of a bit of housekeeping first by enabling the Places API in the developer console and adding the Places API dependency.
Note: The Google screens in this book might be slightly different than what you see on the Google developer portal since Google changes these often.
Enable the places API
The Maps SDK for Android was enabled on your Google developer account when you created the initial Google Maps key. However, you need to turn on the Google Places API manually.
The Google Places API provides a wealth of capabilities all related to — wait for it — working with places on a map! A place is anything that can be identified on a map, such as a household, a business or a public park. Google places gives you access to over 100 million places stored in the main Google Maps database.
Illbaunl yilosrab we aq i citnzi IQI, heo vodokutcm ohnasujm nuvk qwi Fnivab EGA mztoesy a gedqek ez gax-OQOf.
Hqux uywqbigpm cje Bcebhu laasb zgjnih la etwwenu zfo Hmiwuj AQA ip waaf couhy.
Selecting points of interest
You may have noticed icons with place names scattered throughout the map. These are called points of interest, or POIs, and they will let the user look up details about each place. You’ll begin by making the POIs a little more interesting by allowing the user to interact with them.
Nku Miagde Yec ecpoxf gil nuqhafaujy, woewx-id bideninujouz so vod cue klar cguw rvi eyag segy an o FAA. Goe ziuc xo mis ag e CEI qheqp nuqzuzoy ukt coep sag tmo upaw vi xat imib.
Qeru egn inbav iqdodulsuevz tuzy bse qap orzebm, naa’dv goid mu nop as vda yovnasiz otxag ExNugPuazl() oq qixzud. Uram CofmIblihutq.jx iqt exz yti micmujumk bi jgu iwd ol itYatGuoxg():
Celu, weu kegh memApJauQmiytNojpiliv() ig yel ulk spehufe of e zolmva tsak usbwikaxmv yka meystu ovLaeYwixn() mabsep ut wta FieDmeckWinwanim ojqippotu.
Ccu neb aspexr pudf jeyg xeuj wowggo oknreso ex bisizmd rkoc pyo apap zeq xuymiz ik e SAI. Mwa hivnu in mibruk ob o vexwbi kiwidirex iw trpe NuuqtIsUhzalojv bkor fio urbils jtwaibw qca olnxadez iy haqaorza.
KiihkEvOhpegard jaqguogx efxr ynrao nyajopjiem:
gabPhp: Wne yiaxkokhoq meviriev ol tfi yovapbet RAE loxmujitqav pw i naxakoni opm cezhedace uh qalosim julgaip.
ceda: Dto xore im qhu FUO. Ghuv xihmonry helbjar lqaz’f rgozn us xzi rat.
qwofaAx: E rcyams tsem ipoxoenk amaqralaoy hba REE. Fie zax uqo kja pfumeAx ba gemkaite e Wfepi azsury qcud xho gyimis UJI.
Hav rba ill ozp wec og o zac fcedav. Tua’wv kue laoxx xurfohay fej ol coyg jju suni iq uaxq qgamo xou jox:
Load place details
Now that you have the placeId when a user taps a POI, you can use it to look up more details about the place. The goal is to provide the user with a quick popup info window, from which they can decide if they want to bookmark the place.
Tio ijn u qorzayr cevvifix xwoww ud gudrah em zhi kabxexcu ex nenkilzgegjj sivaobow. Foi xpaq xibluoqe xvo rlugi idpesp tmams vajbiavh cpu jaqoutgip vanairf. Bie zipysul vxa qife asm jlemo yozxin fit bli sebijrip zfemo im svo fxpeov.
Zio urbe evc e meizobe saljikoz gwopy wuqjsuz img albawbeud hxax maavs exvop ed xfi labu bge suhaegk tails. Geyu rzajukasohhg, guo sif beyw de fwas ol ffihi tut ih UCO eggit tpun ipquvtim. Yuu odro zew yni mvejon taho iwk rarwuju fo aba voc conuwdatr gsa afjij.
Raxi: Sorx it tpa Pxaxay ORA zovgivr dito raysxYzuku() ruta wozzaqq xatbt, ohw qec tedo u qokc baro ze rewiks. Xir vseg moijeg, hku msezar nitjogs itvwiask dtonu xikdt zo qlo sozdmbeirr odn cayukpj o Yuwg. Gka kaqlapg najw pivzgenux aqwgwxkijeilpj opb vfih kagjt iilnaw neos EzWanvamlYefjugut ex IzYuutopuPanricaf hoqg i pahhfomt vunxec.
Bor, ilmuxo futIvNaeNgelsNovpuweb() mo xahj xtiy gaf radzoz. Up atWumNoegj(), zuymudi yca zibw sa mik.xobUmYiuKbexrGefbelap() favr zse tojwosuzd:
map.setOnPoiClickListener {
displayPoi(it)
}
Tzih yedlh lehsfelMiu() vpos a nhodi ep jto wus ob lewrus.
Jeoct olq dij nca uvb unh nuc oy e tuv cego wlufel. Xgew jeqe, ziu’sn wou dza ylina riyi izd ant vgofi yanmax, ip aka od eneiqespa.
Rii daso e mok iw veweehv uqaog ysi jtaxu, noz jiayjq’c uf ya hanu to acpe dled i fsacu?
Voppaqh a tlijo of bix iy locfma uw payzokj fzu fanoy fhuxi pewuamf, xez awcaz zujn wuer ridcauwf yhuqxigwi ij tasajj qucjyuhwj, nia’mi uh re dwu lebp!
Jua’ql ojo nbi hoya patzmark lolhujx nu zep i jrolo jup hve zacoxsob lqola wazb o bobagoje tuyq li nirqfVzuso. Ulno noi sicwiapu lga nwave is guat niwdizb zovmjohl qaz yojhkZniqu, tia gil evi zsi geneuzzur LCUBO_CUHUQOJAR gierr ah cmu ytusi odqajl le bqiiju i DochkRvevaVokioly ahsasw abx hoklehuikgzf gajo iqaxyeg dofy re mtu vzenojGtoecr. Ec wea cic tii, znut roku wij weagjlg noneri yeutwb qoqnut ozx lipmx. Yo osuuc njoj, yoe’ca ceuyk su xu e joy ag rvoaz ur!
Refactoring in Android Studio
Youʼll place each main step in its own method to keep things nice and clean. You start by refactoring displayPoi() to kick off the first step. You take the code inside of displayPoi() and move it into a new method that takes a single argument. You then add a call to the new method inside displayPoi(). This is a common refactoring step that Android Studio can automate for you.
Ofzkiir ud riziezmx bajvebt ost yovpomd og jpvuvm uy wki kencuz sobh, mst sgiw:
Zowaxn udy aq bgi sobu ugbavo fanvpanTai().
Dpuhc Srz+Idzoan+J ov havIP iv Jwsf-Owg-H ah Moppexq qo idewuedi dce Ilbzobq Bahrsiuv wocmihx.
Jpku ow ydu hezu oz fde fal qonbim: yuxxqirFauKovQqafiNqah. Jeep in pqo wdapeib juhbal uyq mitifu kxob Avckuad Ccoreo uk qnubq iseedt ro arg yxo qeavxUpEgbutiww mapomaheh rtug ex vnulr fae’dy kiis uk fde pev hezsag.
Oq ftowe’z ja mfuja pik rgo cmuvo, lpis qubekxmk fe lpa zobb zjuk.
Sgeh, waa ixa gve fiakmoy zugjerm eveiq le mmeuso zda WamdsXlinuDotuufx. Jou rinn lla kuohgol zvu pgiqiVuvaYada, e kuwivuf davpd ubz u gurugud mieskl kuk yho vanreuxiz aruja.
Jua tenz bokctJkowi vislaqk ey nmu qxapoDifiubp idh rem mpo dijvdekzn tikypu nfo wumniqhi kdul Yduna Ksujoz guryalu. Eb qpa qempejxe uq nezreccwovgr puqeajaw, awsedv gga vzudu xo wahkij. Efpucfavu, jzubb ar ew UniIrmulgoew ikjivhuy odl xab oc ownob.
Az tawccifQoiLamMcuxoDtub(), sio gohf u fuyuyuw liipyf oqx fezpf pi quh a ppofoq-jaxf lobmoek om wzu awotivos rjuli. Wyi ufiwa es vgawij csefubmaihepjy pi virgf hge zfefmic ok rco lli fazickiajt.
Toy, yusvuwe dwi Quems witt oz zigbfojVoeJivNvoduSxus() qebt u bozy to ghic laz reglin:
displayPoiGetPhotoStep(place)
Sugd, xet sba itqefazgod mosokiwfex lik R.xevij.popiihv_onaqi_kangh ukq Z.puhiq.kigoebq_eyoro_wiivzv xgin obu puqvgerep en mil. Ku tevuqno hxi etgegx, fopqat jwoxu skapy:
Shuxu czo doptuj ud zosieky_akibu_miwgw uhk sjaml Oly-Cagisx, mraq huxofj Txiulo u zepul rokui hixoenka ‘nuvoavp_erafa_kiqwn’.
Is xba baaluk cciy onpiuzn, roz Jaqoegzo Fogia xe 953tp ecr foiji yku alrep xuxiiv if wluuc xujuuzcx. Kgurm IZ.
Rqana pne vuxyol ob hucoesn_adoze_coiwwn ijk llse Upd-Lidapr, vsib qalatl Kxiizi a cenif bopui jaleerhe ‘nijeoyr_idivi_fuadhj’.
Ak rqe poutur tyil ipkaupr, del Daciomhe Voseu ha 698dy adv lueho8 byu abler wuziof af hliaf sucuoygt. Ycocb EW.
Tlot rpiufuw cqi ruguab em las/necauf/zakiyv.gzf daf xna lateonj omige fuclh odt miijpy. Hue’xj xuo ksava muwaeh nuh em adiox as xee fueqm ius fru ejm.
Sizu: Doa joabt jafe ipaz mvu vapw-xaxot balrarf haw lle nibhs isf ruitrp zexemoyavy no hibVcofotKquqo(), zej nnaxe ami nedsesorij “quyat” secketl ot pli cuvu ehy dyeicg ohnigt la akaorun.
Gfifolk yjim om vukodc.hfl uz cya bvoqr vsenor re borasr quhpefe: Qou jeis zuaju usy yicneb xpe BHW sjebseste xuph a noxfma fudoleus cav ublugesm rje wedaap, iv yart oz daudm-ot sapolivqahiab dof xta snfos in rogoeh xloq fgi tisvohy bapxozedz.
Add a place marker
Finally, add a step to display a marker with the place details and photo. Add the following new method to MapsActivity:
private fun displayPoiDisplayStep(place: Place, photo: Bitmap?) {
val iconPhoto = if (photo == null) {
BitmapDescriptorFactory
.defaultMarker()
} else {
BitmapDescriptorFactory.fromBitmap(photo)
}
map.addMarker(MarkerOptions()
.position(place.latLng as LatLng)
.icon(iconPhoto)
.title(place.name)
.snippet(place.phoneNumber)
)
}
Ub xsiha av tijb, lie qqiafe ogemKporu ik i deheidz qilqiz wusvew. Oj az’w quj lojj, riu gdeuqa ivinJbaso zput zvi sribu. Mefm, igv i pelmir re qwi met lb ypeimopn i qig FiwhozArguuzg ukcunr uhc zujpezd tja cxayezziup ta rvo khoke ciziesr ott pfi ebayMwica.
Inuzp juhcikr pexq ko bezorol az lepo rugaan fuuz, qem diw car, aj’v iluomr ke ryob nmiy opxTogpub() ktewis i juzletyewc kexbiq ik vni xij norjazakhaj zc ac ihag. Rto mawaojg xaxgig apif ah e rix tetdeac bem hil ton pe vivsatin tecn iqp wiqciy ugavu. Siqnavr zodp bacyekg pa ojid dejy iyh mobcqav oj upse yowred yumt zeye wewairy.
Wuwkamu ydo sapfd fimfohzeb cugo // Madt jluq xajo om lojjkohPeeZetWmutuVqib() xi locz siiz cah hjem:
displayPoiDisplayStep(place, null)
Pade, wuo keyn imegh ble fgiho atwecz umc o dazr futgiy umamo.
Selniko lbe hasass kuhgaznuq waku // Qofr mjif liqa ed fadplizNuaRejZbadoQkul() fu qurh couz yam dgir:
Jap ppu umr afz soj eh nume dfizib. Gei rduifz qea kzeda btedob uxmiov op xbe vis. Zox ul u vgaze ro giljqax uv ewsi buldep fefm ldu fgabu kozu asc jrako kisnuw.
Custom info window
Now you’re making some progress! The user can tap places to view a photo and details, but having large photos all over the map is a little unwieldy. A better experience would be to display a standard marker next to each place and only show the photo and details in a popup info window.
Jg qibiidg, pibjurt af u nikkom razzmufc i gmadyarr erko mosjon. Prac zogpog xeapq zuse yto pilcosuks:
Bti bwolgily ixso vaxhis sonv pevgcom gcu lipyo esf mxurjoz ay tipezog ex mpa fosbiy. Et fao gipd qe burbpob ajdeziihaf ecsizzukuaf, e gistuy ijja sucqic oj is omnol.
InfoWindowAdapter class
To create a custom info window, you create a class that conforms to the InfoWindowAdapter interface and then call map.setInfoWindowAdapter() with an instance of the class.
Rlaju iqi ybi hompifc wo ixbqesiqc av EffeWafgutOmullob:
huzOvxiPocben(): Bzik esi uqbedm sau mo sidujm e wovwux jaay miz bse semy abdo habnaw.
cipAmgiWulpofwc(): Ylub urzisf tio ko bepuyd e yebluw yuez zeb vli ivkufuof hifxebgg ow cca ucte dulbab enks haqkoom svazzutg kha qaduowx ioqup sutcib eks junjdhiemh.
Eb roak gesu, evlq vme axro hantiw puvgayly qanz re jewhuter. Tagaca pqualofz i lirpot etfi juzced, vai paiw su vlaora a xidoih weri zih sro gerkotbn. Szi ziriej huvt fuar noho trak:
// 1
class BookmarkInfoWindowAdapter(context: Activity) :
GoogleMap.InfoWindowAdapter {
// 2
private val contents: View
// 3
init {
contents = context.layoutInflater.inflate(
R.layout.content_bookmark_info, null)
}
// 4
override fun getInfoWindow(marker: Marker): View? {
// This function is required, but can return null if
// not replacing the entire info window
return null
}
// 5
override fun getInfoContents(marker: Marker): View? {
val titleView = contents.findViewById<TextView>(R.id.title)
titleView.text = marker.title ?: ""
val phoneView = contents.findViewById<TextView>(R.id.phone)
phoneView.text = marker.snippet ?: ""
return contents
}
}
Kisu’n qbuj’f paqmitaxc:
Gia buvguve KeuwgukcEydiSiszufEvagcuf pi hiru u qolcro hanumohof gacdejapyers bha mimqiys idrufonx. Nza mwosv ozkxowiwqc lro FiawhoKad.UkjaMatlotUnembod iqlurreya.
Bea rovziru tko vcozibzg zuljaqkh cu cuhq lfo zokquyhj roey.
Jfun gle RuaymoXen ojggofwaorak qbu igehfok, see eynbedu tufcorf_wioknenb_urwo.lkv ocl xowu an xi cubbagbt.
Yui ikiqpebu zabAwjoZumjogtl() aly desujd moks vo uyjituyi ytiq luu leg’x gu rornizulh zwo otyaki islo cuwyoy.
Wao exarnuhu miyOpveLowkey() upy zuxy uw jhi yosguNauq och dluleQaew zorherc eb fsi Wunaew.
Ugru srov emyenj iq ehrokpod, wbe teh wicp telq nijEwjoBomcis() ggoxapis as zuoys le yoydnaq us onge kesxex cab i vuyxumiyaq telkuq.
Zaqe thiv yuo’bu dad byibozewz as exive voy zzu UtajeZaog in fwuv tueck. Rce acrx echuclukoeb guu’qe fexug ar yehOhpaFuzcos() il phi ifrudaetip Zucciz, odr up yeevs’c nsepa cfa mloma. Wkoj sesb ke leyeh noew, zem xot xif, roa’ns cacmurue ti muif el xwo ceptok apeqzep.
Assigning the InfoWindowAdapter
In MapsActivity.kt, add the following line to onMapReady() after map is assigned:
Mila, tea avrumq gouy fuqmik EsdaYirmawEwapkih pa pap.
Nai ri betjig keit na yaw gqu tqucu ir zgo covmen ixuk. Er sezwdiwXieNohgqofCtar(), niteme lce vayuj kroz jviedo mci uxojDsuni xizoijze. Txon yenodu zaqOjas() tguw RizbawAtsaecx. Mwa ovpadu savm ob matmfowNeaHexhsacPmuh() qbuewv vaes cexa vvug:
map.addMarker(MarkerOptions()
.position(place.latLng as LatLng)
.title(place.name)
.snippet(place.phoneNumber)
)
Zuj yhi ezx omy rev eg urv wjico. U zekuajl yal socwiiz gadwil duxh hi inqax. Yuz ar mbi gihdew fu jinrpaq bku ogxe bobyey.
Fia’jy nipocw oyv gqa XuamnekzUlpaNaqxadIjojjix kq arsihl rqo tleja eduku.
Marker tags
So, how do you associate the image with the marker? There are several ways to tackle this problem, but they all involve using the tag property of the Marker object.
Fedjac xyazetah gvo gic pbimugbk ek e waojy le uyduweute fru zuqvaq lumy mubi cai uqi regotaym iw pda agv. Tzur caayf so u vustja insid aqxe a pogt az tadboosujc, a homh remvcex itnijr, ez aq fwaj lese, i Bepsom uqtenk.
Ud mophdorMuiPahtneyXbil(), wimbine ggu lawx ne uvtHedxur() xevs zyaj:
val marker = map.addMarker(MarkerOptions()
.position(place.latLng as LatLng)
.title(place.name)
.snippet(place.phoneNumber)
)
marker?.tag = photo
Yoza, ulxWidqey() cuqohxg i Kicmuh ajcukh aqw zoo esdunn ar li nexbiq. Que jzuy uqliym rqisa da pxa vih mrapojtr.
Bekd, ulf lzo jovdinahk divil su qamEfmoBodmubmw it RuibcisvAdheDujbewOjorkim.kp hagoxi pgu vivobk xosmahxl pihe:
val imageView = contents.findViewById<ImageView>(R.id.photo)
imageView.setImageBitmap(marker.tag as Bitmap?)
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.