अपने Android ऐप्लिकेशन (Kotlin) में मैप जोड़ना

1. शुरू करने से पहले

इस कोडलैब में, Maps SDK for Android को अपने ऐप्लिकेशन के साथ इंटिग्रेट करने का तरीका बताया गया है. साथ ही, इसकी मुख्य सुविधाओं का इस्तेमाल करने के बारे में भी बताया गया है. इसके लिए, एक ऐसा ऐप्लिकेशन बनाया गया है जो अमेरिका के कैलिफ़ोर्निया के सैन फ़्रांसिस्को में मौजूद साइकिल की दुकानों का मैप दिखाता है.

f05e1ca27ff42bf6.png

ज़रूरी शर्तें

  • Kotlin और Android डेवलपमेंट की बुनियादी जानकारी

आपको क्या करना होगा

  • Android ऐप्लिकेशन में Google Maps जोड़ने के लिए, Android के लिए Maps SDK टूल को चालू करें और उसका इस्तेमाल करें.
  • मार्कर जोड़ें, उन्हें पसंद के मुताबिक बनाएं, और उन्हें क्लस्टर करें.
  • मैप पर पॉलीलाइन और पॉलीगॉन बनाएं.
  • प्रोग्राम के हिसाब से कैमरे के व्यू पॉइंट को कंट्रोल करें.

आपको किन चीज़ों की ज़रूरत होगी

2. सेट अप करें

इस सुविधा को चालू करने के लिए , आपको Android के लिए Maps SDK चालू करना होगा.

Google Maps Platform सेट अप करना

अगर आपके पास Google Cloud Platform खाता और बिलिंग की सुविधा वाला प्रोजेक्ट नहीं है, तो बिलिंग की सुविधा वाला खाता और प्रोजेक्ट बनाएं. ऐसा करने का तरीका जानने के लिए, कृपया Google Maps Platform का इस्तेमाल शुरू करना देखें.

  1. Cloud Console में, प्रोजेक्ट वाले ड्रॉप-डाउन मेन्यू पर क्लिक करें. इसके बाद, उस प्रोजेक्ट को चुनें जिसे इस कोडलैब के लिए इस्तेमाल करना है.

  1. इस कोडलैब के लिए ज़रूरी Google Maps Platform API और एसडीके को Google Cloud Marketplace में जाकर चालू करें. ऐसा करने के लिए, इस वीडियो या दस्तावेज़ में बताया गया तरीका अपनाएं.
  2. Cloud Console के क्रेडेंशियल पेज पर जाकर, एक एपीआई पासकोड जनरेट करें. ऐसा करने के लिए, इस वीडियो या दस्तावेज़ में बताया गया तरीका अपनाएं. Google Maps Platform का इस्तेमाल करने के लिए, एपीआई पासकोड ज़रूरी है.

3. तुरंत शुरू करना

इस कोडलैब को जल्द से जल्द शुरू करने के लिए, यहां कुछ शुरुआती कोड दिए गए हैं. आपके पास सीधे समाधान पर जाने का विकल्प है. हालांकि, अगर आपको इसे खुद बनाने के लिए सभी चरणों का पालन करना है, तो पढ़ना जारी रखें.

  1. अगर आपने git इंस्टॉल किया है, तो रिपॉज़िटरी को क्लोन करें.
git clone https://github.com/googlecodelabs/maps-platform-101-android.git

इसके अलावा, सोर्स कोड को डाउनलोड करने के लिए, इस बटन पर क्लिक करें.

  1. कोड मिलने के बाद, Android Studio में starter डायरेक्ट्री में मौजूद प्रोजेक्ट खोलें.

4. Google Maps जोड़ना

इस सेक्शन में, Google Maps को जोड़ा जाएगा, ताकि ऐप्लिकेशन लॉन्च करने पर यह लोड हो जाए.

d1d068b5d4ae38b9.png

अपनी एपीआई कुंजी जोड़ना

पिछले चरण में बनाई गई एपीआई कुंजी को ऐप्लिकेशन को देना होगा, ताकि Maps SDK for Android आपकी कुंजी को आपके ऐप्लिकेशन से जोड़ सके.

  1. इसे उपलब्ध कराने के लिए, अपने प्रोजेक्ट की रूट डायरेक्ट्री में मौजूद local.properties नाम की फ़ाइल खोलें. यह फ़ाइल उसी लेवल पर मौजूद होती है जहां gradle.properties और settings.gradle मौजूद हैं.
  2. उस फ़ाइल में, एक नई कुंजी GOOGLE_MAPS_API_KEY को परिभाषित करें. इसकी वैल्यू, वह एपीआई कुंजी होगी जिसे आपने बनाया है.

local.properties

GOOGLE_MAPS_API_KEY=YOUR_KEY_HERE

ध्यान दें कि local.properties, Git रिपॉज़िटरी में मौजूद .gitignore फ़ाइल में मौजूद है. ऐसा इसलिए है, क्योंकि आपकी एपीआई कुंजी को संवेदनशील जानकारी माना जाता है. इसलिए, अगर हो सके, तो इसे सोर्स कंट्रोल में शामिल नहीं किया जाना चाहिए.

  1. इसके बाद, अपने एपीआई को इस तरह से उपलब्ध कराएं कि इसका इस्तेमाल पूरे ऐप्लिकेशन में किया जा सके. इसके लिए, अपने ऐप्लिकेशन की build.gradle फ़ाइल में Android के लिए सीक्रेट ग्रेडल प्लग इन प्लग इन को शामिल करें. यह फ़ाइल, app/ डायरेक्ट्री में मौजूद होती है. साथ ही, plugins ब्लॉक में यह लाइन जोड़ें:

ऐप्लिकेशन-लेवल की build.gradle फ़ाइल

plugins {
    // ...
    id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
}

आपको अपने प्रोजेक्ट-लेवल की build.gradle फ़ाइल में भी बदलाव करना होगा, ताकि इसमें यह क्लासपाथ शामिल किया जा सके:

प्रोजेक्ट-लेवल build.gradle

buildscript {
    dependencies {
        // ...
        classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:1.3.0"
    }
}

यह प्लगिन, आपकी local.properties फ़ाइल में तय की गई कुंजियों को, Android मेनिफ़ेस्ट फ़ाइल में बिल्ड वैरिएबल के तौर पर उपलब्ध कराएगा. साथ ही, बिल्ड के समय Gradle से जनरेट की गई BuildConfig क्लास में वैरिएबल के तौर पर उपलब्ध कराएगा. इस प्लगिन का इस्तेमाल करने से, बॉयलरप्लेट कोड हट जाता है. बॉयलरप्लेट कोड का इस्तेमाल, local.properties से प्रॉपर्टी पढ़ने के लिए किया जाता है, ताकि इसे आपके पूरे ऐप्लिकेशन में ऐक्सेस किया जा सके.

Google Maps डिपेंडेंसी जोड़ना

  1. अब आपके ऐप्लिकेशन में एपीआई पासकोड को ऐक्सेस किया जा सकता है. इसलिए, अगला चरण यह है कि अपने ऐप्लिकेशन की build.gradle फ़ाइल में, Maps SDK for Android की डिपेंडेंसी जोड़ें.

इस कोडलैब के साथ मिलने वाले स्टार्टर प्रोजेक्ट में, यह डिपेंडेंसी पहले से ही जोड़ दी गई है.

build.gradle

dependencies {
   // Dependency to include Maps SDK for Android
   implementation 'com.google.android.gms:play-services-maps:17.0.0'
}
  1. इसके बाद, AndroidManifest.xml में एक नया meta-data टैग जोड़ें, ताकि एपीआई कुंजी को पास किया जा सके. यह कुंजी आपने पिछले चरण में बनाई थी. इसके लिए, Android Studio में इस फ़ाइल को खोलें. इसके बाद, app/src/main में मौजूद AndroidManifest.xml फ़ाइल में, application ऑब्जेक्ट के अंदर यह meta-data टैग जोड़ें.

AndroidManifest.xml

<meta-data
   android:name="com.google.android.geo.API_KEY"
   android:value="${GOOGLE_MAPS_API_KEY}" />
  1. इसके बाद, app/src/main/res/layout/ डायरेक्ट्री में activity_main.xml नाम की नई लेआउट फ़ाइल बनाएं और उसे इस तरह से तय करें:

activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity">

   <fragment
       class="com.google.android.gms.maps.SupportMapFragment"
       android:id="@+id/map_fragment"
       android:layout_width="match_parent"
       android:layout_height="match_parent" />

</FrameLayout>

इस लेआउट में एक FrameLayout है, जिसमें एक SupportMapFragment शामिल है. इस फ़्रैगमेंट में, वह GoogleMaps ऑब्जेक्ट शामिल होता है जिसका इस्तेमाल बाद के चरणों में किया जाता है.

  1. आखिर में, app/src/main/java/com/google/codelabs/buildyourfirstmap में मौजूद MainActivity क्लास को अपडेट करें. इसके लिए, onCreate तरीके को बदलने के लिए यहां दिया गया कोड जोड़ें, ताकि आपने अभी जो नया लेआउट बनाया है उससे इसके कॉन्टेंट को सेट किया जा सके.

MainActivity

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(R.layout.activity_main)
}
  1. अब ऐप्लिकेशन चलाएं. अब आपको अपने डिवाइस की स्क्रीन पर मैप लोड होता हुआ दिखेगा.

5. क्लाउड पर मैप की स्टाइलिंग (ज़रूरी नहीं)

क्लाउड पर मैप की स्टाइलिंग की सुविधाओं का इस्तेमाल करके, अपने मैप में मनमुताबिक स्टाइल जोड़े जा सकते हैं.

मैप आईडी बनाना

अगर आपने अब तक मैप आईडी नहीं बनाया है और उसे अपने मैप के स्टाइल से नहीं जोड़ा है, तो इसका तरीका जानने और अपनाने के लिए, मैप के आईडी गाइड देखें:

  1. मैप आईडी बनाना.
  2. मैप के किसी स्टाइल से एक मैप आईडी जोड़ना.

अपने ऐप्लिकेशन में मैप आईडी जोड़ना

आपने जो मैप आईडी बनाया है उसका इस्तेमाल करने के लिए, activity_main.xml फ़ाइल में बदलाव करें. साथ ही, SupportMapFragment के map:mapId एट्रिब्यूट में अपना मैप आईडी पास करें.

activity_main.xml

<fragment xmlns:map="http://schemas.android.com/apk/res-auto"
    class="com.google.android.gms.maps.SupportMapFragment"
    <!-- ... -->
    map:mapId="YOUR_MAP_ID" />

यह प्रोसेस पूरी करने के बाद, ऐप्लिकेशन चलाएं और अपने चुने गए स्टाइल में मैप देखें!

6. मार्कर जोड़ना

इस टास्क में, आपको मैप में ऐसे मार्कर जोड़ने हैं जो लोकप्रिय जगहों को दिखाते हैं. ये वे जगहें हैं जिन्हें आपको मैप पर हाइलाइट करना है. सबसे पहले, आपको उन जगहों की सूची मिलती है जो आपके लिए स्टार्टर प्रोजेक्ट में दी गई हैं. इसके बाद, उन जगहों को मैप में जोड़ा जाता है. इस उदाहरण में, ये साइकल की दुकानें हैं.

bc5576877369b554.png

GoogleMap का रेफ़रंस पाना

सबसे पहले, आपको GoogleMap ऑब्जेक्ट का रेफ़रंस पाना होगा, ताकि आप इसके तरीकों का इस्तेमाल कर सकें. इसके लिए, setContentView() को कॉल करने के ठीक बाद, अपने MainActivity.onCreate() तरीके में यह कोड जोड़ें:

MainActivity.onCreate()

val mapFragment = supportFragmentManager.findFragmentById(   
    R.id.map_fragment
) as? SupportMapFragment
mapFragment?.getMapAsync { googleMap ->
    addMarkers(googleMap)
}

लागू करने के दौरान, सबसे पहले SupportMapFragment ऑब्जेक्ट पर findFragmentById() तरीके का इस्तेमाल करके, पिछले चरण में जोड़े गए SupportMapFragment का पता लगाया जाता है.SupportFragmentManager रेफ़रंस मिलने के बाद, getMapAsync() कॉल किया जाता है. इसके बाद, इसमें lambda पास किया जाता है. इस लैम्डा में GoogleMap ऑब्जेक्ट पास किया जाता है. इस लैम्डा के अंदर, addMarkers() तरीके के कॉल को शुरू किया जाता है. इसके बारे में यहां बताया गया है.

दी गई क्लास: PlacesReader

स्टार्टर प्रोजेक्ट में, आपको PlacesReader क्लास दी गई है. यह क्लास, 49 जगहों की सूची को पढ़ती है. यह सूची, places.json नाम की JSON फ़ाइल में सेव होती है. इसके बाद, यह क्लास इन जगहों की सूची को List<Place> के तौर पर दिखाती है. ये जगहें, अमेरिका के कैलिफ़ोर्निया में सैन फ़्रांसिस्को के आस-पास मौजूद साइकिल की दुकानों की सूची दिखाती हैं.

अगर आपको इस क्लास को लागू करने के बारे में ज़्यादा जानना है, तो इसे GitHub पर ऐक्सेस किया जा सकता है. इसके अलावा, Android Studio में PlacesReader क्लास को खोला जा सकता है.

PlacesReader

package com.google.codelabs.buildyourfirstmap.place

import android.content.Context
import com.google.codelabs.buildyourfirstmap.R
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import java.io.InputStream
import java.io.InputStreamReader

/**
* Reads a list of place JSON objects from the file places.json
*/
class PlacesReader(private val context: Context) {

   // GSON object responsible for converting from JSON to a Place object
   private val gson = Gson()

   // InputStream representing places.json
   private val inputStream: InputStream
       get() = context.resources.openRawResource(R.raw.places)

   /**
    * Reads the list of place JSON objects in the file places.json
    * and returns a list of Place objects
    */
   fun read(): List<Place> {
       val itemType = object : TypeToken<List<PlaceResponse>>() {}.type
       val reader = InputStreamReader(inputStream)
       return gson.fromJson<List<PlaceResponse>>(reader, itemType).map {
           it.toPlace()
       }
   }

जगहों की जानकारी लोड करना

साइकल की दुकानों की सूची लोड करने के लिए, MainActivity में places नाम की प्रॉपर्टी जोड़ें और इसे इस तरह से तय करें:

MainActivity.places

private val places: List<Place> by lazy {
   PlacesReader(this).read()
}

यह कोड, PlacesReader पर read() तरीके को लागू करता है. इससे List<Place> मिलता है. Place में name नाम की एक प्रॉपर्टी होती है. यह जगह का नाम होता है. साथ ही, इसमें latLng होता है, जो जगह के निर्देशांक होते हैं.

जगह

data class Place(
   val name: String,
   val latLng: LatLng,
   val address: LatLng,
   val rating: Float
)

मैप में मार्कर जोड़ना

जगहों की सूची को मेमोरी में लोड करने के बाद, अगला चरण इन जगहों को मैप पर दिखाना है.

  1. MainActivity में addMarkers() नाम का एक तरीका बनाएं और उसे इस तरह से तय करें:

MainActivity.addMarkers()

/**
* Adds marker representations of the places list on the provided GoogleMap object
*/
private fun addMarkers(googleMap: GoogleMap) {
   places.forEach { place ->
       val marker = googleMap.addMarker(
           MarkerOptions()
               .title(place.name)
               .position(place.latLng)
       )
   }
}

यह तरीका, places की सूची में दोहराता है. इसके बाद, दिए गए GoogleMap ऑब्जेक्ट पर addMarker() तरीके को शुरू करता है. मार्कर को MarkerOptions ऑब्जेक्ट को इंस्टैंटिएट करके बनाया जाता है. इससे आपको मार्कर को पसंद के मुताबिक बनाने की सुविधा मिलती है. इस मामले में, मार्कर का टाइटल और पोज़िशन दी गई है. यह क्रमशः साइकिल की दुकान का नाम और उसके निर्देशांक दिखाता है.

  1. ऐप्लिकेशन चलाएं और सैन फ़्रांसिस्को पर जाएं. यहां आपको वे मार्कर दिखेंगे जिन्हें आपने अभी-अभी जोड़ा है!

7. मार्कर को पसंद के मुताबिक बनाना

आपने जो मार्कर जोड़े हैं उन्हें पसंद के मुताबिक बनाने के लिए, कई विकल्प उपलब्ध हैं. इससे मार्कर को अलग से दिखाने और लोगों को काम की जानकारी देने में मदद मिलती है. इस टास्क में, आपको कुछ मार्कर के बारे में जानने का मौका मिलेगा. इसके लिए, आपको हर मार्कर की इमेज और मार्कर पर टैप करने पर दिखने वाली जानकारी वाली विंडो को पसंद के मुताबिक बनाना होगा.

a26f82802fe838e9.png

जानकारी वाली विंडो जोड़ना

डिफ़ॉल्ट रूप से, मार्कर पर टैप करने पर जानकारी विंडो में उसका टाइटल और स्निपेट दिखता है. हालांकि, ऐसा तब होता है, जब स्निपेट सेट किया गया हो. इसे अपनी पसंद के मुताबिक बनाया जा सकता है, ताकि यह जगह की रेटिंग और पते जैसी अन्य जानकारी दिखा सके.

marker_info_contents.xml बनाएं

सबसे पहले, marker_info_contents.xml नाम की नई लेआउट फ़ाइल बनाएं.

  1. इसके लिए, Android Studio में प्रोजेक्ट व्यू में मौजूद app/src/main/res/layout फ़ोल्डर पर राइट क्लिक करें. इसके बाद, New > Layout Resource File को चुनें.

8cac51fcbef9171b.png

  1. डायलॉग बॉक्स में, फ़ाइल का नाम फ़ील्ड में marker_info_contents और Root element फ़ील्ड में LinearLayout टाइप करें. इसके बाद, ठीक है पर क्लिक करें.

8783af12baf07a80.png

इस लेआउट फ़ाइल को बाद में बड़ा किया जाता है, ताकि जानकारी वाली विंडो में कॉन्टेंट दिखाया जा सके.

  1. यहां दिए गए कोड स्निपेट में मौजूद कॉन्टेंट को कॉपी करें. इससे वर्टिकल LinearLayout व्यू ग्रुप में तीन TextViews जुड़ जाते हैं. इसके बाद, फ़ाइल में मौजूद डिफ़ॉल्ट कोड को बदलें.

marker_info_contents.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:orientation="vertical"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:gravity="center_horizontal"
   android:padding="8dp">

   <TextView
       android:id="@+id/text_view_title"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:textColor="@android:color/black"
       android:textSize="18sp"
       android:textStyle="bold"
       tools:text="Title"/>

   <TextView
       android:id="@+id/text_view_address"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:textColor="@android:color/black"
       android:textSize="16sp"
       tools:text="123 Main Street"/>

   <TextView
       android:id="@+id/text_view_rating"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:textColor="@android:color/black"
       android:textSize="16sp"
       tools:text="Rating: 3"/>

</LinearLayout>

InfoWindowAdapter का इस्तेमाल करना

कस्टम जानकारी वाली विंडो के लिए लेआउट फ़ाइल बनाने के बाद, अगला चरण GoogleMap.InfoWindowAdapter इंटरफ़ेस को लागू करना है. इस इंटरफ़ेस में दो तरीके होते हैं: getInfoWindow() और getInfoContents(). दोनों तरीकों से एक वैकल्पिक View ऑब्जेक्ट मिलता है. पहले तरीके का इस्तेमाल, विंडो को पसंद के मुताबिक बनाने के लिए किया जाता है. वहीं, दूसरे तरीके का इस्तेमाल, विंडो के कॉन्टेंट को पसंद के मुताबिक बनाने के लिए किया जाता है. आपके मामले में, आपने दोनों को लागू किया है. साथ ही, getInfoWindow() में शून्य वैल्यू दिखाते समय, getInfoContents() की वैल्यू को पसंद के मुताबिक बनाया है. इससे पता चलता है कि डिफ़ॉल्ट विंडो का इस्तेमाल किया जाना चाहिए.

  1. Android Studio में प्रोजेक्ट व्यू में मौजूद app/src/main/java/com/google/codelabs/buildyourfirstmap फ़ोल्डर पर राइट क्लिक करके, MainActivity के जैसा ही पैकेज इस्तेमाल करने वाली नई Kotlin फ़ाइल MarkerInfoWindowAdapter बनाएं. इसके बाद, नया > Kotlin फ़ाइल/क्लास चुनें.

3975ba36eba9f8e1.png

  1. डायलॉग बॉक्स में, MarkerInfoWindowAdapter टाइप करें और File को हाइलाइट किया हुआ रखें.

992235af53d3897f.png

  1. फ़ाइल बनाने के बाद, यहां दिए गए कोड स्निपेट में मौजूद कॉन्टेंट को अपनी नई फ़ाइल में कॉपी करें.

MarkerInfoWindowAdapter

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.Marker
import com.google.codelabs.buildyourfirstmap.place.Place

class MarkerInfoWindowAdapter(
    private val context: Context
) : GoogleMap.InfoWindowAdapter {
   override fun getInfoContents(marker: Marker?): View? {
       // 1. Get tag
       val place = marker?.tag as? Place ?: return null

       // 2. Inflate view and set title, address, and rating
       val view = LayoutInflater.from(context).inflate(
           R.layout.marker_info_contents, null
       )
       view.findViewById<TextView>(
           R.id.text_view_title
       ).text = place.name
       view.findViewById<TextView>(
           R.id.text_view_address
       ).text = place.address
       view.findViewById<TextView>(
           R.id.text_view_rating
       ).text = "Rating: %.2f".format(place.rating)

       return view
   }

   override fun getInfoWindow(marker: Marker?): View? {
       // Return null to indicate that the 
       // default window (white bubble) should be used
       return null
   }
}

getInfoContents() तरीके के कॉन्टेंट में, तरीके में दिए गए मार्कर को Place टाइप में कास्ट किया जाता है. अगर कास्टिंग मुमकिन नहीं है, तो तरीका शून्य दिखाता है. आपने अब तक Marker पर टैग प्रॉपर्टी सेट नहीं की है, लेकिन अगले चरण में ऐसा किया जाएगा.

इसके बाद, लेआउट marker_info_contents.xml को बड़ा किया जाता है. इसके बाद, TextViews टैग में मौजूद टेक्स्ट को Place टैग पर सेट किया जाता है.

MainActivity को अपडेट करें

अब तक बनाए गए सभी कॉम्पोनेंट को एक साथ जोड़ने के लिए, आपको अपनी MainActivity क्लास में दो लाइनें जोड़नी होंगी.

सबसे पहले, कस्टम InfoWindowAdapter, MarkerInfoWindowAdapter को पास करने के लिए, getMapAsync तरीके के कॉल में, GoogleMap ऑब्जेक्ट पर setInfoWindowAdapter() तरीके को लागू करें और MarkerInfoWindowAdapter का नया इंस्टेंस बनाएं.

  1. इसके लिए, getMapAsync() लैंबडा में addMarkers() तरीके के कॉल के बाद, यह कोड जोड़ें.

MainActivity.onCreate()

// Set custom info window adapter
googleMap.setInfoWindowAdapter(MarkerInfoWindowAdapter(this))

आखिर में, आपको मैप में जोड़े गए हर मार्कर पर, हर जगह को टैग प्रॉपर्टी के तौर पर सेट करना होगा.

  1. इसके लिए, addMarkers() फ़ंक्शन में places.forEach{} कॉल में यह बदलाव करें:

MainActivity.addMarkers()

places.forEach { place ->
   val marker = googleMap.addMarker(
       MarkerOptions()
           .title(place.name)
           .position(place.latLng)
           .icon(bicycleIcon)
   )

   // Set place as the tag on the marker object so it can be referenced within
   // MarkerInfoWindowAdapter
   marker.tag = place
}

कस्टम मार्कर इमेज जोड़ना

मार्कर की इमेज को पसंद के मुताबिक बनाना, यह बताने का एक मज़ेदार तरीका है कि मार्कर आपके मैप पर किस तरह की जगह को दिखाता है. इस चरण में, मैप पर हर दुकान को दिखाने के लिए, डिफ़ॉल्ट लाल मार्कर के बजाय साइकिलें दिखाई जाती हैं. स्टार्टर प्रोजेक्ट में, app/src/res/drawable में मौजूद ic_directions_bike_black_24dp.xml वाला साइकल आइकॉन शामिल होता है. इसका इस्तेमाल किया जाता है.

6eb7358bb61b0a88.png

मार्कर पर कस्टम बिटमैप सेट करना

आपके पास वेक्टर ड्रॉएबल साइकल आइकॉन है. अब आपको इस ड्रॉएबल को मैप पर मौजूद हर मार्कर के आइकॉन के तौर पर सेट करना है. MarkerOptions में icon नाम का एक तरीका है. यह BitmapDescriptor को इनपुट के तौर पर लेता है. इसका इस्तेमाल इस काम को पूरा करने के लिए किया जाता है.

सबसे पहले, आपको अभी जोड़े गए वेक्टर ड्रॉएबल को BitmapDescriptor में बदलना होगा. स्टार्टर प्रोजेक्ट में शामिल BitMapHelper नाम की फ़ाइल में, vectorToBitmap() नाम का एक हेल्पर फ़ंक्शन होता है. यह फ़ंक्शन, सिर्फ़ यही काम करता है.

BitmapHelper

package com.google.codelabs.buildyourfirstmap

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.util.Log
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.DrawableCompat
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.BitmapDescriptorFactory

object BitmapHelper {
   /**
    * Demonstrates converting a [Drawable] to a [BitmapDescriptor], 
    * for use as a marker icon. Taken from ApiDemos on GitHub:
    * https://github.com/googlemaps/android-samples/blob/main/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/MarkerDemoActivity.kt
    */
   fun vectorToBitmap(
      context: Context,
      @DrawableRes id: Int, 
      @ColorInt color: Int
   ): BitmapDescriptor {
       val vectorDrawable = ResourcesCompat.getDrawable(context.resources, id, null)
       if (vectorDrawable == null) {
           Log.e("BitmapHelper", "Resource not found")
           return BitmapDescriptorFactory.defaultMarker()
       }
       val bitmap = Bitmap.createBitmap(
           vectorDrawable.intrinsicWidth,
           vectorDrawable.intrinsicHeight,
           Bitmap.Config.ARGB_8888
       )
       val canvas = Canvas(bitmap)
       vectorDrawable.setBounds(0, 0, canvas.width, canvas.height)
       DrawableCompat.setTint(vectorDrawable, color)
       vectorDrawable.draw(canvas)
       return BitmapDescriptorFactory.fromBitmap(bitmap)
   }
}

इस तरीके में, Context, ड्रॉ किए जा सकने वाले संसाधन का आईडी, और रंग का पूर्णांक शामिल होता है. साथ ही, यह इसका BitmapDescriptor बनाता है.

सहायक तरीके का इस्तेमाल करके, bicycleIcon नाम की नई प्रॉपर्टी का एलान करें और इसे यह परिभाषा दें: MainActivity.bicycleIcon

private val bicycleIcon: BitmapDescriptor by lazy {
   val color = ContextCompat.getColor(this, R.color.colorPrimary)
   BitmapHelper.vectorToBitmap(this, R.drawable.ic_directions_bike_black_24dp, color)
}

यह प्रॉपर्टी, आपके ऐप्लिकेशन में पहले से तय किए गए रंग colorPrimary का इस्तेमाल करती है. साथ ही, इसका इस्तेमाल करके, साइकल के आइकॉन को रंग देती है और उसे BitmapDescriptor के तौर पर दिखाती है.

  1. इस प्रॉपर्टी का इस्तेमाल करके, addMarkers() तरीके में MarkerOptions के icon तरीके को लागू करें, ताकि आइकॉन को पसंद के मुताबिक बनाया जा सके. ऐसा करने पर, मार्कर प्रॉपर्टी कुछ इस तरह दिखनी चाहिए:

MainActivity.addMarkers()

val marker = googleMap.addMarker(
    MarkerOptions()
        .title(place.name)
        .position(place.latLng)
        .icon(bicycleIcon)
)
  1. अपडेट किए गए मार्कर देखने के लिए, ऐप्लिकेशन चलाएं!

8. क्लस्टर मार्कर

मैप को ज़ूम इन करने पर, आपने शायद देखा होगा कि जोड़े गए मार्कर एक-दूसरे पर ओवरलैप हो रहे हैं. ओवरलैप होने वाले मार्कर के साथ इंटरैक्ट करना बहुत मुश्किल होता है. साथ ही, इससे बहुत ज़्यादा नॉइज़ पैदा होती है. इससे आपके ऐप्लिकेशन के इस्तेमाल पर असर पड़ता है.

68591edc86d73724.png

उपयोगकर्ताओं को बेहतर अनुभव देने के लिए, जब भी आपके पास ऐसा बड़ा डेटासेट हो जिसमें डेटा पॉइंट एक-दूसरे के काफ़ी करीब हों, तो मार्कर क्लस्टरिंग लागू करना सबसे सही तरीका है. क्लस्टरिंग की सुविधा की मदद से, मैप में ज़ूम इन और आउट करने पर, आस-पास मौजूद मार्कर एक साथ क्लस्टर हो जाते हैं. जैसे:

f05e1ca27ff42bf6.png

इसे लागू करने के लिए, आपको Maps SDK for Android Utility Library की मदद लेनी होगी.

Android Utility Library के लिए Maps SDK

Android के लिए Maps SDK टूल की यूटिलिटी लाइब्रेरी को, Android के लिए Maps SDK टूल की सुविधाओं को बेहतर बनाने के लिए बनाया गया था. इसमें बेहतर सुविधाएं मिलती हैं. जैसे, मार्कर क्लस्टरिंग, हीटमैप, KML और GeoJson सपोर्ट, पॉलीलाइन एन्कोडिंग और डिकोडिंग, और स्फ़ेरिकल ज्यामिति के लिए कुछ हेल्पर फ़ंक्शन.

build.gradle फ़ाइल अपडेट करना

यूटिलिटी लाइब्रेरी को Maps SDK for Android से अलग पैकेज किया जाता है. इसलिए, आपको अपनी build.gradle फ़ाइल में एक और डिपेंडेंसी जोड़नी होगी.

  1. आगे बढ़ें और अपनी app/build.gradle फ़ाइल के dependencies सेक्शन को अपडेट करें.

build.gradle

implementation 'com.google.maps.android:android-maps-utils:1.1.0'
  1. इस लाइन को जोड़ने के बाद, नई डिपेंडेंसी फ़ेच करने के लिए, आपको प्रोजेक्ट सिंक करना होगा.

b7b030ec82c007fd.png

क्लस्टरिंग लागू करना

अपने ऐप्लिकेशन पर क्लस्टरिंग लागू करने के लिए, यह तरीका अपनाएं:

  1. ClusterItem इंटरफ़ेस लागू करें.
  2. DefaultClusterRenderer क्लास की सबक्लास बनाएं.
  3. ClusterManager बनाएं और उसमें आइटम जोड़ें.

ClusterItem इंटरफ़ेस लागू करना

मैप पर क्लस्टर किए जा सकने वाले मार्कर को दिखाने वाले सभी ऑब्जेक्ट को ClusterItem इंटरफ़ेस लागू करना होगा. आपके मामले में, इसका मतलब है कि Place मॉडल को ClusterItem के मुताबिक होना चाहिए. Place.kt फ़ाइल खोलें और इसमें ये बदलाव करें:

जगह

data class Place(
   val name: String,
   val latLng: LatLng,
   val address: String,
   val rating: Float
) : ClusterItem {
   override fun getPosition(): LatLng =
       latLng

   override fun getTitle(): String =
       name

   override fun getSnippet(): String =
       address
}

ClusterItem इन तीन तरीकों के बारे में बताता है:

  • getPosition(), जो जगह की LatLng को दिखाता है.
  • getTitle(), जो जगह के नाम को दिखाता है
  • getSnippet(), जो जगह के पते को दिखाता है.

DefaultClusterRenderer क्लास की सबक्लास बनाएं

क्लस्टरिंग लागू करने वाली क्लास, ClusterManager, इंटरनल तौर पर ClusterRenderer क्लास का इस्तेमाल करती है. इससे, मैप को पैन और ज़ूम करने पर क्लस्टर बनाए जाते हैं. डिफ़ॉल्ट रूप से, इसमें डिफ़ॉल्ट रेंडरर, DefaultClusterRenderer होता है. यह ClusterRenderer को लागू करता है. सामान्य मामलों में, यह जानकारी काफ़ी है. हालांकि, आपके मामले में मार्कर को पसंद के मुताबिक बनाने की ज़रूरत है. इसलिए, आपको इस क्लास को बढ़ाना होगा और उसमें अपनी पसंद के मुताबिक बदलाव करने होंगे.

आगे बढ़ें और पैकेज com.google.codelabs.buildyourfirstmap.place में Kotlin फ़ाइल PlaceRenderer.kt बनाएं. इसके बाद, इसे इस तरह से तय करें:

PlaceRenderer

package com.google.codelabs.buildyourfirstmap.place

import android.content.Context
import androidx.core.content.ContextCompat
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.MarkerOptions
import com.google.codelabs.buildyourfirstmap.BitmapHelper
import com.google.codelabs.buildyourfirstmap.R
import com.google.maps.android.clustering.ClusterManager
import com.google.maps.android.clustering.view.DefaultClusterRenderer

/**
* A custom cluster renderer for Place objects.
*/
class PlaceRenderer(
   private val context: Context,
   map: GoogleMap,
   clusterManager: ClusterManager<Place>
) : DefaultClusterRenderer<Place>(context, map, clusterManager) {

   /**
    * The icon to use for each cluster item
    */
   private val bicycleIcon: BitmapDescriptor by lazy {
       val color = ContextCompat.getColor(context,
           R.color.colorPrimary
       )
       BitmapHelper.vectorToBitmap(
           context,
           R.drawable.ic_directions_bike_black_24dp,
           color
       )
   }

   /**
    * Method called before the cluster item (the marker) is rendered.
    * This is where marker options should be set.
    */
   override fun onBeforeClusterItemRendered(
      item: Place,
      markerOptions: MarkerOptions
   ) {
       markerOptions.title(item.name)
           .position(item.latLng)
           .icon(bicycleIcon)
   }

   /**
    * Method called right after the cluster item (the marker) is rendered.
    * This is where properties for the Marker object should be set.
    */
   override fun onClusterItemRendered(clusterItem: Place, marker: Marker) {
       marker.tag = clusterItem
   }
}

यह क्लास इन दो फ़ंक्शन को ओवरराइड करती है:

  • onBeforeClusterItemRendered(), जिसे मैप पर क्लस्टर रेंडर होने से पहले कॉल किया जाता है. यहां, MarkerOptions के ज़रिए पसंद के मुताबिक बदलाव किए जा सकते हैं. इस मामले में, यह मार्कर का टाइटल, पोज़िशन, और आइकॉन सेट करता है.
  • onClusterItemRenderer(), जिसे मार्कर को मैप पर रेंडर करने के तुरंत बाद कॉल किया जाता है. यहां बनाए गए Marker ऑब्जेक्ट को ऐक्सेस किया जा सकता है. इस मामले में, यह मार्कर की टैग प्रॉपर्टी सेट करता है.

ClusterManager बनाना और आइटम जोड़ना

आखिर में, क्लस्टरिंग की सुविधा को चालू करने के लिए, आपको MainActivity में बदलाव करना होगा, ताकि ClusterManager को इंस्टैंटिएट किया जा सके. साथ ही, इसे ज़रूरी डिपेंडेंसी दी जा सकें. ClusterManager, मार्कर (ClusterItem ऑब्जेक्ट) को अंदरूनी तौर पर जोड़ने का काम करता है. इसलिए, मार्कर को सीधे मैप पर जोड़ने के बजाय, यह ज़िम्मेदारी ClusterManager को सौंपी जाती है. इसके अलावा, ClusterManager इंटरनल तौर पर setInfoWindowAdapter() को भी कॉल करता है. इसलिए, कस्टम जानकारी वाली विंडो सेट करने के लिए, ClusterManger के MarkerManager.Collection ऑब्जेक्ट का इस्तेमाल करना होगा.

  1. शुरू करने के लिए, MainActivity.onCreate() में getMapAsync() कॉल में लैंबडा के कॉन्टेंट में बदलाव करें. आगे बढ़ें और addMarkers() और setInfoWindowAdapter() को कॉल करने के लिए टिप्पणी करें. इसके बजाय, addClusteredMarkers() नाम के तरीके को लागू करें, जिसे आपको आगे तय करना है.

MainActivity.onCreate()

mapFragment?.getMapAsync { googleMap ->
    //addMarkers(googleMap)
    addClusteredMarkers(googleMap)

    // Set custom info window adapter.
    // googleMap.setInfoWindowAdapter(MarkerInfoWindowAdapter(this))
}
  1. इसके बाद, MainActivity में जाकर addClusteredMarkers() को परिभाषित करें.

MainActivity.addClusteredMarkers()

/**
* Adds markers to the map with clustering support.
*/
private fun addClusteredMarkers(googleMap: GoogleMap) {
   // Create the ClusterManager class and set the custom renderer.
   val clusterManager = ClusterManager<Place>(this, googleMap)
   clusterManager.renderer =
       PlaceRenderer(
           this,
           googleMap,
           clusterManager
       )

   // Set custom info window adapter
   clusterManager.markerCollection.setInfoWindowAdapter(MarkerInfoWindowAdapter(this))

   // Add the places to the ClusterManager.
   clusterManager.addItems(places)
   clusterManager.cluster()

   // Set ClusterManager as the OnCameraIdleListener so that it
   // can re-cluster when zooming in and out.
   googleMap.setOnCameraIdleListener {
       clusterManager.onCameraIdle()
   }
}

इस तरीके से, ClusterManager को इंस्टैंशिएट किया जाता है. साथ ही, कस्टम रेंडरर PlacesRenderer को पास किया जाता है. इसके बाद, सभी जगहों को जोड़ा जाता है और cluster() तरीके को लागू किया जाता है. इसके अलावा, ClusterManager मैप ऑब्जेक्ट पर setInfoWindowAdapter() तरीके का इस्तेमाल करता है. इसलिए, कस्टम जानकारी वाली विंडो को ClusterManager.markerCollection ऑब्जेक्ट पर सेट करना होगा. आखिर में, आपको क्लस्टरिंग में बदलाव तब करना है, जब उपयोगकर्ता मैप को पैन और ज़ूम करे. इसलिए, OnCameraIdleListener को googleMap के साथ उपलब्ध कराया जाता है, ताकि जब कैमरा बंद हो जाए, तब clusterManager.onCameraIdle() को चालू किया जा सके.

  1. अब ऐप्लिकेशन चलाकर, क्लस्टर की गई नई दुकानें देखें!

9. मैप पर जानकारी देने के लिए ड्रॉ करना

आपने मैप पर ड्रॉ करने का एक तरीका पहले ही देख लिया है. यह तरीका मार्कर जोड़ने का है. हालांकि, Maps SDK for Android में कई अन्य तरीके भी उपलब्ध हैं. इनकी मदद से, मैप पर काम की जानकारी दिखाई जा सकती है.

उदाहरण के लिए, अगर आपको मैप पर रास्ते और इलाके दिखाने हैं, तो मैप पर इन्हें दिखाने के लिए पॉलीलाइन और पॉलीगॉन का इस्तेमाल किया जा सकता है. इसके अलावा, अगर आपको किसी इमेज को ज़मीन की सतह पर सेट करना है, तो ग्राउंड ओवरले का इस्तेमाल करें.

इस टास्क में, आपको यह सिखाया जाएगा कि मार्कर पर टैप करने पर, उसके चारों ओर शेप, खास तौर पर सर्कल कैसे बनाया जाता है.

f98ce13055430352.png

क्लिक लिसनर जोड़ना

आम तौर पर, मार्कर में क्लिक लिसनर जोड़ने के लिए, GoogleMap ऑब्जेक्ट में setOnMarkerClickListener() के ज़रिए सीधे तौर पर क्लिक लिसनर पास किया जाता है. हालांकि, क्लस्टरिंग का इस्तेमाल करने की वजह से, क्लिक लिसनर को ClusterManager को देना होगा.

  1. MainActivity में addClusteredMarkers() तरीके का इस्तेमाल करते समय, cluster() को इनवोक करने के ठीक बाद यह लाइन जोड़ें.

MainActivity.addClusteredMarkers()

// Show polygon
clusterManager.setOnClusterItemClickListener { item ->
   addCircle(googleMap, item)
   return@setOnClusterItemClickListener false
}

इस तरीके से एक लिसनर जोड़ा जाता है और addCircle() तरीके को लागू किया जाता है. इसे आपको अगले चरण में तय करना होता है. आखिर में, false को इस तरीके से वापस कर दिया जाता है. इससे पता चलता है कि इस तरीके ने इस इवेंट का इस्तेमाल नहीं किया है.

  1. इसके बाद, आपको MainActivity में प्रॉपर्टी circle और तरीके addCircle() के बारे में बताना होगा.

MainActivity.addCircle()

private var circle: Circle? = null

/**
* Adds a [Circle] around the provided [item]
*/
private fun addCircle(googleMap: GoogleMap, item: Place) {
   circle?.remove()
   circle = googleMap.addCircle(
       CircleOptions()
           .center(item.latLng)
           .radius(1000.0)
           .fillColor(ContextCompat.getColor(this, R.color.colorPrimaryTranslucent))
           .strokeColor(ContextCompat.getColor(this, R.color.colorPrimary))
   )
}

circle प्रॉपर्टी को इस तरह से सेट किया गया है कि जब भी किसी नए मार्कर पर टैप किया जाता है, तो पिछला सर्कल हट जाता है और एक नया सर्कल जुड़ जाता है. ध्यान दें कि सर्कल जोड़ने के लिए एपीआई, मार्कर जोड़ने के लिए एपीआई से काफ़ी मिलता-जुलता है.

  1. अब ऐप्लिकेशन को चलाकर देखें कि बदलाव हुए हैं या नहीं.

10. कैमरे को कंट्रोल करना

आखिरी टास्क के तौर पर, कुछ कैमरा कंट्रोल देखें, ताकि किसी खास जगह पर फ़ोकस किया जा सके.

कैमरा और व्यू

अगर आपने ऐप्लिकेशन को चलाते समय ध्यान दिया हो, तो कैमरा अफ़्रीका महाद्वीप को दिखाता है. इसके बाद, आपको सैन फ़्रांसिस्को में जोड़े गए मार्कर ढूंढने के लिए, पैन और ज़ूम करना पड़ता है. यह दुनिया को एक्सप्लोर करने का एक मज़ेदार तरीका हो सकता है. हालांकि, अगर आपको मार्कर तुरंत दिखाने हैं, तो यह तरीका काम का नहीं है.

इसके लिए, कैमरे की पोज़िशन को प्रोग्राम के हिसाब से सेट किया जा सकता है, ताकि व्यू को आपकी पसंद के हिसाब से सेंटर में रखा जा सके.

  1. आगे बढ़ें और getMapAsync() कॉल में यह कोड जोड़ें, ताकि कैमरे के व्यू को अडजस्ट किया जा सके. इससे, ऐप्लिकेशन लॉन्च होने पर, यह सैन फ़्रांसिस्को पर सेट हो जाएगा.

MainActivity.onCreate()

mapFragment?.getMapAsync { googleMap ->
   // Ensure all places are visible in the map.
   googleMap.setOnMapLoadedCallback {
       val bounds = LatLngBounds.builder()
       places.forEach { bounds.include(it.latLng) }
       googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), 20))
   }
}

सबसे पहले, setOnMapLoadedCallback() को कॉल किया जाता है, ताकि मैप लोड होने के बाद ही कैमरे को अपडेट किया जा सके. यह चरण ज़रूरी है, क्योंकि कैमरा अपडेट कॉल करने से पहले, मैप की प्रॉपर्टी (जैसे कि डाइमेंशन) का हिसाब लगाना होता है.

लैंबडा में, एक नया LatLngBounds ऑब्जेक्ट बनाया जाता है. यह ऑब्जेक्ट, मैप पर एक आयताकार क्षेत्र तय करता है. इसे धीरे-धीरे बनाया जाता है. इसके लिए, इसमें सभी जगह की LatLng वैल्यू शामिल की जाती हैं, ताकि यह पक्का किया जा सके कि सभी जगहें सीमा के अंदर हैं. इस ऑब्जेक्ट के बन जाने के बाद, GoogleMap पर मौजूद moveCamera() तरीके को चालू किया जाता है. साथ ही, CameraUpdateFactory.newLatLngBounds(bounds.build(), 20) के ज़रिए इसे CameraUpdate उपलब्ध कराया जाता है.

  1. ऐप्लिकेशन चलाएं और देखें कि सैन फ़्रांसिस्को में कैमरा अब शुरू हो गया है.

कैमरे में होने वाले बदलावों को सुनना

कैमरे की पोज़िशन में बदलाव करने के साथ-साथ, उपयोगकर्ता के मैप पर घूमने के दौरान कैमरे के अपडेट भी सुने जा सकते हैं. अगर आपको कैमरे के घूमने के साथ-साथ यूज़र इंटरफ़ेस (यूआई) में बदलाव करना है, तो यह आपके काम आ सकता है.

सिर्फ़ मज़े के लिए, कैमरे को हिलाने पर मार्कर को पारदर्शी बनाने के लिए कोड में बदलाव करें.

  1. addClusteredMarkers() तरीके में, इस तरीके के सबसे नीचे दी गई लाइनें जोड़ें:

MainActivity.addClusteredMarkers()

// When the camera starts moving, change the alpha value of the marker to translucent.
googleMap.setOnCameraMoveStartedListener {
   clusterManager.markerCollection.markers.forEach { it.alpha = 0.3f }
   clusterManager.clusterMarkerCollection.markers.forEach { it.alpha = 0.3f }
}

इससे एक OnCameraMoveStartedListener जुड़ जाता है, ताकि जब भी कैमरा हिलना शुरू करे, तो सभी मार्कर (क्लस्टर और मार्कर, दोनों) की ऐल्फ़ा वैल्यू को 0.3f में बदल दिया जाए. इससे मार्कर पारदर्शी दिखते हैं.

  1. आखिर में, जब कैमरा बंद हो जाए, तब पारदर्शी मार्कर को फिर से अपारदर्शी बनाने के लिए, setOnCameraIdleListener में मौजूद कॉन्टेंट को addClusteredMarkers() तरीके से बदलें:

MainActivity.addClusteredMarkers()

googleMap.setOnCameraIdleListener {
   // When the camera stops moving, change the alpha value back to opaque.
   clusterManager.markerCollection.markers.forEach { it.alpha = 1.0f }
   clusterManager.clusterMarkerCollection.markers.forEach { it.alpha = 1.0f }

   // Call clusterManager.onCameraIdle() when the camera stops moving so that reclustering
   // can be performed when the camera stops moving.
   clusterManager.onCameraIdle()
}
  1. नतीजे देखने के लिए, ऐप्लिकेशन चलाएं!

11. Maps KTX

एक या एक से ज़्यादा Google Maps Platform Android SDK का इस्तेमाल करने वाले Kotlin ऐप्लिकेशन के लिए, Kotlin एक्सटेंशन या KTX लाइब्रेरी उपलब्ध हैं. इनकी मदद से, Kotlin लैंग्वेज की सुविधाओं का फ़ायदा लिया जा सकता है. जैसे, कोराउटीन, एक्सटेंशन प्रॉपर्टी/फ़ंक्शन वगैरह. हर Google Maps SDK के लिए, उससे जुड़ी KTX लाइब्रेरी होती है. यहां इसकी जानकारी दी गई है:

Google Maps Platform KTX का डायग्राम

इस टास्क में, आपको अपने ऐप्लिकेशन में Maps KTX और Maps Utils KTX लाइब्रेरी का इस्तेमाल करना होगा. साथ ही, पिछले टास्क के कोड को फिर से लिखना होगा, ताकि अपने ऐप्लिकेशन में Kotlin की खास सुविधाओं का इस्तेमाल किया जा सके.

  1. ऐप्लिकेशन-लेवल की build.gradle फ़ाइल में KTX डिपेंडेंसी शामिल करना

ऐप्लिकेशन, Maps SDK for Android और Maps SDK for Android Utility Library, दोनों का इस्तेमाल करता है. इसलिए, आपको इन लाइब्रेरी के लिए, KTX लाइब्रेरी शामिल करनी होंगी. इस टास्क में, AndroidX Lifecycle KTX लाइब्रेरी में मौजूद किसी सुविधा का इस्तेमाल किया जाएगा. इसलिए, ऐप्लिकेशन-लेवल की build.gradle फ़ाइल में उस डिपेंडेंसी को भी शामिल करें.

build.gradle

dependencies {
    // ...

    // Maps SDK for Android KTX Library
    implementation 'com.google.maps.android:maps-ktx:3.0.0'

    // Maps SDK for Android Utility Library KTX Library
    implementation 'com.google.maps.android:maps-utils-ktx:3.0.0'

    // Lifecycle Runtime KTX Library
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
}
  1. GoogleMap.addMarker() और GoogleMap.addCircle() एक्सटेंशन फ़ंक्शन का इस्तेमाल करना

Maps KTX लाइब्रेरी, पिछले चरणों में इस्तेमाल किए गए GoogleMap.addMarker(MarkerOptions) और GoogleMap.addCircle(CircleOptions) के लिए, डीएसएल-स्टाइल एपीआई का विकल्प देती है. ऊपर बताए गए एपीआई का इस्तेमाल करने के लिए, मार्कर या सर्कल के विकल्पों वाली क्लास बनाना ज़रूरी है. वहीं, KTX के विकल्पों के साथ, मार्कर या सर्कल के विकल्प, दिए गए लैम्डा में सेट किए जा सकते हैं.

इन एपीआई का इस्तेमाल करने के लिए, MainActivity.addMarkers(GoogleMap) और MainActivity.addCircle(GoogleMap) तरीकों को अपडेट करें:

MainActivity.addMarkers(GoogleMap)

/**
 * Adds markers to the map. These markers won't be clustered.
 */
private fun addMarkers(googleMap: GoogleMap) {
    places.forEach { place ->
        val marker = googleMap.addMarker {
            title(place.name)
            position(place.latLng)
            icon(bicycleIcon)
        }
        // Set place as the tag on the marker object so it can be referenced within
        // MarkerInfoWindowAdapter
        marker.tag = place
    }
}

MainActivity.addCircle(GoogleMap)

/**
 * Adds a [Circle] around the provided [item]
 */
private fun addCircle(googleMap: GoogleMap, item: Place) {
    circle?.remove()
    circle = googleMap.addCircle {
        center(item.latLng)
        radius(1000.0)
        fillColor(ContextCompat.getColor(this@MainActivity, R.color.colorPrimaryTranslucent))
        strokeColor(ContextCompat.getColor(this@MainActivity, R.color.colorPrimary))
    }
}

ऊपर दिए गए तरीकों को इस तरह से फिर से लिखने पर, उन्हें पढ़ना ज़्यादा आसान हो जाता है. ऐसा Kotlin के रिसीवर के साथ फ़ंक्शन लिटरल का इस्तेमाल करके किया जा सकता है.

  1. SupportMapFragment.awaitMap() और GoogleMap.awaitMapLoad() एक्सटेंशन के निलंबन वाले फ़ंक्शन का इस्तेमाल करें

Maps KTX लाइब्रेरी, कोरूटीन में इस्तेमाल किए जाने वाले सस्पेंडिंग फ़ंक्शन एक्सटेंशन भी उपलब्ध कराती है. खास तौर पर, SupportMapFragment.getMapAsync(OnMapReadyCallback) और GoogleMap.setOnMapLoadedCallback(OnMapLoadedCallback) के लिए, सस्पेंड करने वाले फ़ंक्शन के विकल्प मौजूद हैं. इन वैकल्पिक एपीआई का इस्तेमाल करने पर, कॉलबैक पास करने की ज़रूरत नहीं होती. इसके बजाय, आपको इन तरीकों का जवाब क्रमवार और सिंक्रोनस तरीके से मिलता है.

ये तरीके, फ़ंक्शन को निलंबित करने वाले तरीके हैं. इसलिए, इनका इस्तेमाल किसी कोरूटीन में ही किया जा सकेगा. Lifecycle Runtime KTX लाइब्रेरी, लाइफ़साइकल के बारे में जानकारी रखने वाले को-रूटीन स्कोप उपलब्ध कराने के लिए एक एक्सटेंशन देती है. इससे को-रूटीन, लाइफ़साइकल के सही इवेंट पर चलते और रुकते हैं.

इन दोनों कॉन्सेप्ट को मिलाकर, MainActivity.onCreate(Bundle) तरीके को अपडेट करें:

MainActivity.onCreate(Bundle)

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val mapFragment =
        supportFragmentManager.findFragmentById(R.id.map_fragment) as SupportMapFragment
    lifecycleScope.launchWhenCreated {
        // Get map
        val googleMap = mapFragment.awaitMap()

        // Wait for map to finish loading
        googleMap.awaitMapLoad()

        // Ensure all places are visible in the map
        val bounds = LatLngBounds.builder()
        places.forEach { bounds.include(it.latLng) }
        googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), 20))

        addClusteredMarkers(googleMap)
    }
}

lifecycleScope.launchWhenCreated को-रूटीन स्कोप, गतिविधि के कम से कम क्रिएटेड स्टेट में होने पर ब्लॉक को एक्ज़ीक्यूट करेगा. यह भी ध्यान दें कि GoogleMap ऑब्जेक्ट को वापस पाने के लिए किए गए कॉल और मैप के लोड होने का इंतज़ार करने के लिए किए गए कॉल को क्रमशः SupportMapFragment.awaitMap() और GoogleMap.awaitMapLoad() से बदल दिया गया है. इन सस्पेंडिंग फ़ंक्शन का इस्तेमाल करके कोड को रिफ़ैक्टर करने से, आपको कॉल बैक पर आधारित कोड को क्रमवार तरीके से लिखने में मदद मिलती है.

  1. अब ऐप्लिकेशन को फिर से बनाएं और उसमें रिफ़ैक्टर किए गए बदलावों को शामिल करें!

12. बधाई हो

बधाई हो! आपने काफ़ी कॉन्टेंट कवर कर लिया है. हमें उम्मीद है कि आपको Android के लिए Maps SDK में उपलब्ध मुख्य सुविधाओं के बारे में बेहतर जानकारी मिल गई होगी.

ज़्यादा जानें

  • Places SDK for Android—अपने आस-पास के कारोबारों के बारे में जानने के लिए, जगहों की जानकारी का ज़्यादा से ज़्यादा डेटा एक्सप्लोर करें.
  • android-maps-ktx—यह एक ओपन सोर्स लाइब्रेरी है. इसकी मदद से, Maps SDK for Android और Maps SDK for Android Utility Library को Kotlin के साथ आसानी से इंटिग्रेट किया जा सकता है.
  • android-place-ktx—यह एक ओपन सोर्स लाइब्रेरी है. इसकी मदद से, Places SDK for Android को Kotlin के साथ आसानी से इंटिग्रेट किया जा सकता है.
  • android-samples—GitHub पर मौजूद सैंपल कोड. इसमें इस कोडलैब में बताई गई सभी सुविधाओं के बारे में बताया गया है. साथ ही, इसमें और भी सुविधाएं शामिल हैं.
  • Google Maps Platform की मदद से Android ऐप्लिकेशन बनाने के लिए, Kotlin के ज़्यादा कोडलैब