1. Vorbereitung
In diesem Codelab erfahren Sie, wie Sie das Places SDK for Android in Ihre App einbinden und die einzelnen Funktionen des SDK verwenden.
Vorbereitung
- Grundkenntnisse in Kotlin und Android-Entwicklung
Lerninhalte
- So installieren Sie das Places SDK for Android mit Kotlin-Erweiterungen.
- So laden Sie Ortsdetails für einen bestimmten Ort.
- So fügen Sie ein Place Autocomplete-Widget in Ihre App ein.
- So laden Sie den aktuellen Ort basierend auf dem derzeit gemeldeten Standort des Geräts.
Voraussetzungen
Für dieses Codelab benötigen Sie die folgenden Konten, Dienste und Tools:
- Ein Google-Konto mit aktivierter Abrechnung.
- Android Studio Bumblebee oder höher.
- Google Play-Dienste sind in Android Studio installiert.
- Ein Android-Gerät oder ein Android-Emulator, auf dem die Google APIs-Plattform auf Basis von Android 8 oder höher ausgeführt wird (Installationsanleitung).
2. Einrichten
Aktivieren Sie im folgenden Schritt die Places API und das Maps SDK for Android.
Google Maps Platform einrichten
Wenn Sie noch kein Google Cloud-Konto und kein Projekt mit aktivierter Abrechnung haben, lesen Sie bitte den Leitfaden Erste Schritte mit Google Maps Platform, um ein Rechnungskonto und ein Projekt zu erstellen.
- Klicken Sie in der Cloud Console auf das Drop-down-Menü für das Projekt und wählen Sie das Projekt aus, das Sie für dieses Codelab verwenden möchten.
- Aktivieren Sie die für dieses Codelab erforderlichen APIs und SDKs der Google Maps Platform im Google Cloud Marketplace. Folgen Sie dazu der Anleitung in diesem Video oder dieser Dokumentation.
- Generieren Sie einen API-Schlüssel in der Cloud Console auf der Seite Anmeldedaten. Folgen Sie dazu dieser Anleitung oder dieser Dokumentation. Für alle Anfragen an die Google Maps Platform ist ein API-Schlüssel erforderlich.
3. Schnelleinstieg
Laden Sie den Startcode herunter, damit Sie dieses Codelab nachvollziehen können. Sie können natürlich direkt zur Lösung springen. Wenn Sie die Lösung jedoch selbst erstellen möchten, lesen Sie weiter.
- Klonen Sie das Repository, wenn Sie
git
installiert haben.
git clone https://github.com/googlemaps/codelab-places-101-android-kotlin.git
Alternativ können Sie auf diese Schaltfläche klicken, um den Quellcode herunterzuladen.
- Öffnen Sie nach dem Herunterladen des Codes das Projekt im Verzeichnis
/starter
in Android Studio. Dieses Projekt enthält die grundlegende Dateistruktur, die Sie für das Codelab benötigen. Alle benötigten Dateien befinden sich im Verzeichnis/starter
.
Wenn Sie den vollständigen Lösungscode sehen möchten, können Sie ihn im Verzeichnis /solution
aufrufen.
4. API-Schlüssel zum Projekt hinzufügen
In diesem Abschnitt wird beschrieben, wie Sie Ihren API-Schlüssel speichern, damit er von Ihrer App sicherer referenziert werden kann. Er sollte nicht in Ihrem Versionsverwaltungssystem eingecheckt werden. Stattdessen empfehlen wir Ihnen, ihn in der Datei secrets.properties
zu speichern, die in Ihrer lokalen Kopie des Stammverzeichnisses Ihres Projekts abgelegt wird. Weitere Informationen zur Datei secrets.properties
finden Sie unter Gradle-Attributdateien.
Sie können das Secrets Gradle-Plug-in für Android verwenden, um diese Aufgabe zu optimieren.
So installieren Sie das Secrets Gradle-Plug-in für Android in Ihrem Google Maps-Projekt:
- Öffnen Sie in Android Studio die Datei
build.gradle.kts
oderbuild.gradle
auf oberster Ebene und fügen Sie den folgenden Code in dasdependencies
-Element unterbuildscript
ein.
Wenn Sie build.gradle.kts
verwenden, fügen Sie Folgendes hinzu:
buildscript {
dependencies {
classpath("com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1")
}
}
Wenn Sie build.gradle
verwenden, fügen Sie Folgendes hinzu:
buildscript {
dependencies {
classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1"
}
}
- Öffnen Sie die Datei
build.gradle.kts
oderbuild.gradle
auf Modulebene und fügen Sie den folgenden Code in dasplugins
-Element ein.
Wenn Sie build.gradle.kts
verwenden, fügen Sie Folgendes hinzu:
plugins {
// ...
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
}
Wenn Sie build.gradle
verwenden, fügen Sie Folgendes hinzu:
plugins {
// ...
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
}
- In der Datei
build.gradle.kts
oderbuild.gradle
auf Modulebene müssentargetSdk
undcompileSdk
auf 34 gesetzt sein. - Speichern Sie die Datei und synchronisieren Sie Ihr Projekt mit Gradle.
- Öffnen Sie die Datei
secrets.properties
im Verzeichnis der obersten Ebene und fügen Sie den folgenden Code ein. Ersetzen Sie dabeiYOUR_API_KEY
durch Ihren eigenen API-Schlüssel. Speichern Sie den Schlüssel in dieser Datei, dasecrets.properties
nicht in ein Versionsverwaltungssystem eingecheckt werden kann.
PLACES_API_KEY=YOUR_API_KEY
- Speichern Sie die Datei.
- Erstellen Sie die Datei
local.defaults.properties
im Verzeichnis der obersten Ebene, im selben Ordner wie die Dateisecrets.properties
, und fügen Sie folgenden Code ein.
PLACES_API_KEY=DEFAULT_API_KEY
Diese Datei ist ein Ersatzspeicherort für den API-Schlüssel, damit Builds nicht fehlschlagen, falls die Datei secrets.properties
nicht gefunden wird. Das kann passieren, wenn Sie die App aus einem Versionsverwaltungssystem klonen, in dem secrets.properties
nicht vorhanden ist, und noch keine lokale Datei secrets.properties
erstellt haben, um Ihren API-Schlüssel bereitzustellen.
- Speichern Sie die Datei.
- Öffnen Sie in Android Studio die Datei
build.gradle.kts
oderbuild.gradle
auf Modulebene und bearbeiten Sie das Attributsecrets
. Wenn die Propertysecrets
nicht vorhanden ist, fügen Sie sie hinzu.
Bearbeiten Sie die Attribute des Plug-ins, um propertiesFileName
auf secrets.properties
, defaultPropertiesFileName
auf local.defaults.properties
und alle anderen Attribute festzulegen.
secrets {
// Optionally specify a different file name containing your secrets.
// The plugin defaults to "local.properties"
propertiesFileName = "secrets.properties"
// A properties file containing default secret values. This file can be
// checked in version control.
defaultPropertiesFileName = "local.defaults.properties"
}
5. Places SDK for Android installieren
In diesem Abschnitt fügen Sie die Abhängigkeiten des Places SDK for Android in Ihre App ein.
- Nachdem auf Ihren API-Schlüssel in der App zugegriffen werden kann, fügen Sie die Abhängigkeit für das Places SDK for Android in die Datei
build.gradle
Ihrer App ein.
Fügen Sie der Datei build.gradle
auf App-Ebene die Abhängigkeit für das Places SDK for Android hinzu:
build.gradle-Datei auf App-Ebene
dependencies {
// Dependency to include Places SDK for Android
implementation 'com.google.android.libraries.places:places:3.4.0'
}
- Starten Sie die App.
Sie sollten jetzt eine App mit einem leeren Bildschirm sehen. Füge diesem Bildschirm drei Demos hinzu.
6. Places Android KTX installieren
Für Kotlin-Apps, die ein oder mehrere Google Maps Platform Android SDKs verwenden, können Sie mit KTX-Bibliotheken (Kotlin Extensions) Kotlin-Sprachfunktionen wie Koroutinen, Erweiterungseigenschaften/-funktionen und mehr nutzen. Für jedes Google Maps SDK gibt es eine entsprechende KTX-Bibliothek, wie unten dargestellt:
In dieser Aufgabe verwenden Sie die Places Android KTX-Bibliothek, um Kotlin-spezifische Sprachfunktionen in Ihrer App zu nutzen.
Places Android KTX-Abhängigkeit hinzufügen
Wenn Sie Kotlin-spezifische Funktionen nutzen möchten, fügen Sie die entsprechende KTX-Bibliothek für dieses SDK in Ihre build.gradle
-Datei auf App-Ebene ein.
build.gradle
dependencies {
// ...
// Places SDK for Android KTX Library
implementation 'com.google.maps.android:places-ktx:3.1.1'
}
7. Places-Client initialisieren
Places SDK für den Anwendungsbereich initialisieren
Initialisieren Sie das Places SDK for Android in der Datei DemoApplication.kt
des Ordners app/src/main/java/com/google/codelabs/maps/placesdemo
. Fügen Sie die folgenden Zeilen am Ende der Funktion onCreate
ein:
// Initialize the SDK with the Google Maps Platform API key
Places.initialize(this, BuildConfig.PLACES_API_KEY)
Wenn Sie Ihre App erstellen, wird der API-Schlüssel in Ihrer secrets.properties
-Datei über das Secrets Gradle-Plug-in für Android als BuildConfig.PLACES_API_KEY
verfügbar gemacht.
Anwendungsdatei zum Manifest hinzufügen
Da Sie Application
mit DemoApplication
erweitert haben, müssen Sie das Manifest aktualisieren. Fügen Sie dem Element application
in der Datei AndroidManifest.xml
, die sich in app/src/main
befindet, das Attribut android:name
hinzu:
<application
android:name=".DemoApplication"
...
</application>
Mit diesem Code wird im Anwendungsmanifest auf die Klasse DemoApplication
im Ordner src/main/java/com/google/codelabs/maps/placesdemo/
verwiesen.
8. Ortsdetails abrufen
Detailbildschirm erstellen
Ein activity_details.xml
-Layout mit einem leeren LinearLayout
ist im Ordner app/src/main/res/layout/
verfügbar. Fügen Sie den folgenden Code zwischen den <LinearLayout>
-Klammern ein, um das lineare Layout zu füllen.
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/details_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/details_input_hint"
android:text="@string/details_input_default" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/details_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/button_details" />
<TextView
android:id="@+id/details_response_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:textIsSelectable="true" />
Mit diesem Code wird ein Texteingabefeld hinzugefügt, in das der Nutzer eine beliebige Orts-ID eingeben oder den bereitgestellten Standardwert verwenden kann. Außerdem wird eine Schaltfläche zum Initiieren der „Place Details“-Anfrage und eine TextView zum Anzeigen der Informationen aus der Antwort hinzugefügt. Die zugehörigen Strings sind für Sie in der Datei src/main/res/values/strings.xml
definiert.
Detailaktivität erstellen
- Erstellen Sie im Ordner
src/main/java/com/google/codelabs/maps/placesdemo/
eine DateiDetailsActivity.kt
und verknüpfen Sie sie mit dem gerade erstellten Layout. Fügen Sie diesen Code in die Datei ein:
@ExperimentalCoroutinesApi
class DetailsActivity : AppCompatActivity() {
private lateinit var placesClient: PlacesClient
private lateinit var detailsButton: Button
private lateinit var detailsInput: TextInputEditText
private lateinit var responseView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_details)
// Set up view objects
detailsInput = findViewById(R.id.details_input)
detailsButton = findViewById(R.id.details_button)
responseView = findViewById(R.id.details_response_content)
val apiKey = BuildConfig.PLACES_API_KEY
// Log an error if apiKey is not set.
if (apiKey.isEmpty() || apiKey == "DEFAULT_API_KEY") {
Log.e(TAG, "No api key")
finish()
return
}
}
}
- Erstellen Sie einen Places-Client für die Verwendung mit dieser Aktivität. Fügen Sie diesen Code nach dem Code zum Prüfen des API-Schlüssels in der Funktion
onCreate
ein.
// Retrieve a PlacesClient (previously initialized - see DemoApplication)
placesClient = Places.createClient(this)
- Nachdem der Places Client eingerichtet wurde, hängen Sie einen Klick-Listener an die Schaltfläche an. Fügen Sie diesen Code nach der Erstellung des Places-Clients in die Funktion
onCreate
ein.
// Upon button click, fetch and display the Place Details
detailsButton.setOnClickListener { button ->
button.isEnabled = false
val placeId = detailsInput.text.toString()
val placeFields = listOf(
Place.Field.NAME,
Place.Field.ID,
Place.Field.LAT_LNG,
Place.Field.ADDRESS
)
lifecycleScope.launch {
try {
val response = placesClient.awaitFetchPlace(placeId, placeFields)
responseView.text = response.prettyPrint()
} catch (e: Exception) {
e.printStackTrace()
responseView.text = e.message
}
button.isEnabled = true
}
}
Mit diesem Code wird die Orts-ID abgerufen, die in das Eingabefeld eingegeben wurde. Außerdem wird definiert, welche Felder für den Ort angefordert werden sollen. Dann wird ein FetchPlaceRequest
erstellt, die Aufgabe wird gestartet und es wird auf Erfolg oder Fehler gewartet. Wenn die Anfrage erfolgreich ist, werden die angeforderten Details in der TextView angezeigt.
Aktivität „Details“ dem Manifest hinzufügen
Fügen Sie in der Datei AndroidManifest.xml
unter app/src/main
ein <activity>
-Element für die DetailsActivity
als untergeordnetes Element des <application>
-Elements hinzu:
<activity android:name=".DetailsActivity" android:label="@string/details_demo_title" />
Aktivität „Details“ dem Demomenü hinzufügen
Ein leeres Demo
-Modul wird bereitgestellt, um die verfügbaren Demos auf dem Startbildschirm aufzulisten. Nachdem Sie eine Aktivität für Ortsdetails erstellt haben, fügen Sie sie mit diesem Code der Datei Demo.kt
im Ordner src/main/java/com/google/codelabs/maps/placesdemo/
hinzu:
DETAILS_FRAGMENT_DEMO(
R.string.details_demo_title,
R.string.details_demo_description,
DetailsActivity::class.java
),
Die zugehörigen Strings sind in der Datei src/main/res/values/strings.xml
definiert.
Sehen Sie sich MainActivity.kt
an. Dort wird eine ListView erstellt, die durch Iterieren durch den Inhalt des Moduls Demo
gefüllt wird. Wenn der Nutzer auf ein Element in der Liste tippt, öffnet der Klick-Listener die zugehörige Aktivität.
Anwendung ausführen
- Führen Sie die App aus. Dieses Mal sollte ein Element in der Liste angezeigt werden, das die Demo für Ortsdetails enthält.
- Tippen Sie auf den Text „Ortsdetails“. Sie sollten die von Ihnen erstellte Ansicht mit einem Eingabefeld und einer Schaltfläche sehen.
- Tippen Sie auf die Schaltfläche „DETAILS ANSEHEN“. Wenn Sie die Standard-Orts-ID verwendet haben, sollten der Ortsname, die Adresse und die Kartenkoordinaten angezeigt werden, wie in Abbildung 1 dargestellt.
Abbildung 1. Aktivität „Ortsdetails“ mit angezeigter Antwort.
9. „Place Autocomplete“ verwenden
Bildschirm für die automatische Vervollständigung erstellen
Ein activity_autocomplete.xml
-Layout mit einem leeren LinearLayout
ist im Ordner app/src/main/res/layout/
verfügbar. Fügen Sie diesen Code zwischen den <LinearLayout>
-Klammern ein, um das lineare Layout zu erstellen.
<androidx.fragment.app.FragmentContainerView
android:id="@+id/autocomplete_fragment"
android:background="@android:color/white"
android:name="com.google.android.libraries.places.widget.AutocompleteSupportFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/autocomplete_response_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:textIsSelectable="true" />
Dieser Code fügt ein AutocompleteSupportFragment
-Widget und eine TextView hinzu, um die Informationen aus der Antwort anzuzeigen. Die zugehörigen Strings sind in der Datei src/main/res/values/strings.xml
definiert.
Aktivität zur automatischen Vervollständigung erstellen
- Erstellen Sie eine
AutocompleteActivity.kt
-Datei im Ordnersrc/main/java/com/google/codelabs/maps/placesdemo/
und definieren Sie sie mit diesem Code:
@ExperimentalCoroutinesApi
class AutocompleteActivity : AppCompatActivity() {
private lateinit var responseView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_autocomplete)
// Set up view objects
responseView = findViewById(R.id.autocomplete_response_content)
val autocompleteFragment =
supportFragmentManager.findFragmentById(R.id.autocomplete_fragment)
as AutocompleteSupportFragment
}
}
Mit diesem Code wird die Aktivität den Ansichten und AutocompleteSupportFramgent
zugeordnet, die Sie in der Layoutdatei definiert haben.
- Legen Sie als Nächstes fest, was passiert, wenn der Nutzer einen der von Place Autocomplete präsentierten Vorschläge auswählt. Fügen Sie diesen Code am Ende der Funktion
onCreate
ein:
val placeFields: List<Place.Field> =
listOf(Place.Field.NAME, Place.Field.ID, Place.Field.ADDRESS, Place.Field.LAT_LNG)
autocompleteFragment.setPlaceFields(placeFields)
// Listen to place selection events
lifecycleScope.launchWhenCreated {
autocompleteFragment.placeSelectionEvents().collect { event ->
when (event) {
is PlaceSelectionSuccess -> {
val place = event.place
responseView.text = prettyPrintAutocompleteWidget(place, false)
}
is PlaceSelectionError -> Toast.makeText(
this@AutocompleteActivity,
"Failed to get place '${event.status.statusMessage}'",
Toast.LENGTH_SHORT
).show()
}
}
}
Dieser Code definiert, welche Felder für den Ort angefordert werden sollen, und wartet auf ein Ereignis zur Ortsauswahl sowie auf Erfolg oder Fehler. Wenn die Anfrage erfolgreich ist, werden die Ortsdetails in der TextView angezeigt. Beachten Sie, dass Place Autocomplete ein Place-Objekt zurückgibt. Wenn Sie das Place Autocomplete-Widget verwenden, ist keine separate „Place Details“-Anfrage erforderlich.
Autocomplete-Aktivität dem Manifest hinzufügen
Fügen Sie in der Datei AndroidManifest.xml
unter app/src/main
ein <activity>
-Element für die AutocompleteActivity
als untergeordnetes Element des <application>
-Elements hinzu:
<activity android:name=".AutocompleteActivity" android:label="@string/autocomplete_fragment_demo_title" />
Autocomplete-Aktivität dem Demomenü hinzufügen
Fügen Sie die Place Autocomplete-Demo wie zuvor dem Startbildschirm hinzu, indem Sie sie an die Liste im Demo
-Modul anhängen. Nachdem Sie eine Place Autocomplete-Aktivität erstellt haben, fügen Sie sie der Datei Demo.kt
im Ordner src/main/java/com/google/codelabs/maps/placesdemo/
hinzu. Fügen Sie diesen Code direkt nach dem Element DETAILS_FRAGMENT_DEMO
ein:
AUTOCOMPLETE_FRAGMENT_DEMO(
R.string.autocomplete_fragment_demo_title,
R.string.autocomplete_fragment_demo_description,
AutocompleteActivity::class.java
),
Die zugehörigen Strings sind in der Datei src/main/res/values/strings.xml
definiert.
Anwendung ausführen
- Führen Sie die App aus. Dieses Mal sollten Sie zwei Elemente in der Liste auf dem Startbildschirm sehen.
- Tippen Sie auf die Zeile „Place Autocomplete“. Es sollte ein Place Autocomplete-Eingabefeld wie in Abbildung 2 angezeigt werden.
- Geben Sie den Namen eines Orts ein. Das kann ein Name, eine Adresse oder eine geografische Region sein. Vorhersagen sollten während der Eingabe angezeigt werden.
- Wählen Sie einen der Vorschläge aus. Die Vorhersagen sollten verschwinden und im TextView sollten jetzt die Details zum ausgewählten Ort angezeigt werden, wie in Abbildung 3 dargestellt.
Abbildung 2: Automatische Vervollständigung von Aktivitäten, nachdem der Nutzer auf das Eingabefeld getippt hat.
Abbildung 3: Aktivität zur automatischen Vervollständigung, in der Ortsdetails angezeigt werden, nachdem der Nutzer „Niagara Falls“ eingegeben und ausgewählt hat.
10. Aktuellen Ort des Geräts abrufen
Bildschirm „Aktueller Ort“ erstellen
Im Ordner app/src/main/res/layout/
wurde ein activity_current.xml
-Layout mit einem leeren LinearLayout
bereitgestellt. Fügen Sie den folgenden Code zwischen den <LinearLayout>
-Klammern ein, um das lineare Layout zu füllen.
<Button
android:id="@+id/current_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/current_button" />
<TextView
android:id="@+id/current_response_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:scrollbars = "vertical"
android:textIsSelectable="true" />
„Aktueller Ort“-Aktivität erstellen
- Erstellen Sie eine
CurrentPlaceActivity.kt
-Datei im Ordnersrc/main/java/com/google/codelabs/maps/placesdemo/
und definieren Sie sie mit diesem Code:
@ExperimentalCoroutinesApi
class CurrentPlaceActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var placesClient: PlacesClient
private lateinit var currentButton: Button
private lateinit var responseView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_current)
// Retrieve a PlacesClient (previously initialized - see DemoApplication)
placesClient = Places.createClient(this)
// Set view objects
currentButton = findViewById(R.id.current_button)
responseView = findViewById(R.id.current_response_content)
// Set listener for initiating Current Place
currentButton.setOnClickListener {
checkPermissionThenFindCurrentPlace()
}
}
}
Mit diesem Code wird die Aktivität den Ansichten zugeordnet, die Sie in der Layoutdatei definiert haben. Außerdem wird ein Click-Listener für die Schaltfläche hinzugefügt, um die Funktion checkPermissionThenFindCurrentPlace
aufzurufen, wenn auf die Schaltfläche geklickt wird.
- Definieren Sie
checkPermissionThenFindCurrentPlace()
, um die Berechtigung für den genauen Standort zu prüfen und die Berechtigung anzufordern, falls sie noch nicht erteilt wurde. Fügen Sie diesen Code nach deronCreate
-Funktion ein.
/**
* Checks that the user has granted permission for fine or coarse location.
* If granted, finds current Place.
* If not yet granted, launches the permission request.
* See https://developer.android.com/training/permissions/requesting
*/
private fun checkPermissionThenFindCurrentPlace() {
when {
(ContextCompat.checkSelfPermission(
this,
ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(
this,
ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED) -> {
// You can use the API that requires the permission.
findCurrentPlace()
}
shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)
-> {
Log.d(TAG, "Showing permission rationale dialog")
// TODO: In an educational UI, explain to the user why your app requires this
// permission for a specific feature to behave as expected. In this UI,
// include a "cancel" or "no thanks" button that allows the user to
// continue using your app without granting the permission.
}
else -> {
// Ask for both the ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permissions.
ActivityCompat.requestPermissions(
this,
arrayOf(
ACCESS_FINE_LOCATION,
ACCESS_COARSE_LOCATION
),
PERMISSION_REQUEST_CODE
)
}
}
}
companion object {
private const val TAG = "CurrentPlaceActivity"
private const val PERMISSION_REQUEST_CODE = 9
}
- Wenn im
else
-Zweig der FunktioncheckPermissionThenFindCurrentPlace
die FunktionrequestPermissions
aufgerufen wird, wird dem Nutzer in der App ein Dialogfeld mit einer Berechtigungsanfrage angezeigt. Wenn der Nutzer ein Gerät mit einer niedrigeren Version als Android 12 verwendet, kann er nur die Berechtigung für den genauen (feinen) Standort gewähren. Wenn der Nutzer ein Gerät mit Android 12 oder höher verwendet, hat er die Möglichkeit, anstelle des genauen Standorts den ungefähren Standort anzugeben (siehe Abbildung 4).
Abbildung 4: Wenn Sie auf einem Gerät mit Android 12 oder höher eine Nutzerberechtigung anfordern, haben Sie die Möglichkeit, den genauen oder ungefähren Standort zu gewähren.
Nachdem der Nutzer auf das Dialogfeld für Systemberechtigungen geantwortet hat, ruft das System die Implementierung von onRequestPermissionsResult
in Ihrer App auf. Das System übergibt die Nutzerantwort auf das Berechtigungsdialogfeld sowie den von Ihnen definierten Anfragecode. Überschreiben Sie onRequestPermissionResult
, um den Anfragecode für die Standortberechtigungen im Zusammenhang mit dieser Aktivität „Aktueller Ort“ zu verarbeiten. Fügen Sie dazu den folgenden Code unter checkPermissionThenFindCurrentPlace
ein.
@SuppressLint("MissingPermission")
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>, grantResults: IntArray
) {
if (requestCode != PERMISSION_REQUEST_CODE) {
super.onRequestPermissionsResult(
requestCode,
permissions,
grantResults
)
return
} else if (
permissions.toList().zip(grantResults.toList())
.firstOrNull { (permission, grantResult) ->
grantResult == PackageManager.PERMISSION_GRANTED && (permission == ACCESS_FINE_LOCATION || permission == ACCESS_COARSE_LOCATION)
} != null
)
// At least one location permission has been granted, so proceed with Find Current Place
findCurrentPlace()
}
- Nachdem die Berechtigung erteilt wurde, wird die Funktion
findCurrentPlace
ausgeführt. Definieren Sie die Funktion mit diesem Code nach der FunktiononRequestPermissionsResult
.
/**
* Fetches a list of [PlaceLikelihood] instances that represent the Places the user is
* most likely to be at currently.
*/
@RequiresPermission(anyOf = [ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION])
private fun findCurrentPlace() {
// Use fields to define the data types to return.
val placeFields: List<Place.Field> =
listOf(Place.Field.NAME, Place.Field.ID, Place.Field.ADDRESS, Place.Field.LAT_LNG)
// Call findCurrentPlace and handle the response (first check that the user has granted permission).
if (ContextCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED
) {
// Retrieve likely places based on the device's current location
currentButton.isEnabled = false
lifecycleScope.launch {
val response = placesClient.awaitFindCurrentPlace(placeFields)
responseView.text = response.prettyPrint()
// Enable scrolling on the long list of likely places
val movementMethod = ScrollingMovementMethod()
responseView.movementMethod = movementMethod
}
} else {
Log.d(TAG, "LOCATION permission not granted")
checkPermissionThenFindCurrentPlace()
}
}
Dieser Code definiert, welche Felder für die wahrscheinlichen Orte angefordert werden sollen, erstellt ein FindCurrentPlaceRequest
, initiiert die Aufgabe und füllt die TextView mit den angeforderten Details.
Aktivität „Aktueller Ort“ dem Manifest hinzufügen
Fügen Sie in der Datei AndroidManifest.xml
unter app/src/main
ein <activity>
-Element für die CurrentPlaceActivity
als untergeordnetes Element des <application>
-Elements hinzu:
<activity android:name=".CurrentPlaceActivity" android:label="@string/current_demo_title" />
Aktivität „Aktueller Ort“ dem Demomenü hinzufügen
Fügen Sie die Demo „Aktueller Ort“ wie zuvor dem Startbildschirm hinzu, indem Sie sie der Liste im Modul Demo
anhängen. Nachdem Sie eine „Aktueller Ort“-Aktivität erstellt haben, fügen Sie sie der Datei Demo.kt
im Ordner src/main/java/com/google/codelabs/maps/placesdemo/
hinzu. Fügen Sie diesen Code direkt nach dem Element AUTOCOMPLETE_FRAGMENT_DEMO
ein:
CURRENT_FRAGMENT_DEMO(
R.string.current_demo_title,
R.string.current_demo_description,
CurrentPlaceActivity::class.java
),
Die zugehörigen Strings sind in der Datei src/main/res/values/strings.xml
definiert.
Anwendung ausführen
- Führen Sie die App aus. Dieses Mal sollten drei Elemente in der Liste auf dem Startbildschirm angezeigt werden.
- Tippen Sie auf die Zeile „Aktueller Ort“. Auf dem Bildschirm sollte eine Schaltfläche angezeigt werden.
- Tippe auf die Schaltfläche. Wenn Sie dieser App noch keine Berechtigung zur Standortermittlung erteilt haben, sollte eine Berechtigungsanfrage angezeigt werden.
- Erteilen Sie der App die Berechtigung, auf den Standort des Geräts zuzugreifen.
- Tippen Sie noch einmal auf die Schaltfläche. Nun sollte eine Liste mit bis zu 20 Orten in der Nähe und den entsprechenden Wahrscheinlichkeiten angezeigt werden (siehe Abbildung 5).
Abbildung 5: Es werden wahrscheinliche Übereinstimmungen für den aktuellen Ort des Geräts angezeigt.
11. Aktuellen Ort auf einer Karte anzeigen
Maps-Abhängigkeit hinzufügen
Fügen Sie in der Datei build.gradle
auf Modulebene die Google Play-Dienste-Abhängigkeit für das Maps SDK for Android ein.
app/build.gradle
dependencies {
// ...
implementation 'com.google.android.gms:play-services-maps:18.2.0'
}
Android-Manifest für Karten aktualisieren
Fügen Sie die folgenden meta-data
-Elemente in das application
-Element ein.
Damit wird die Version der Google Play-Dienste eingebettet, mit der die App kompiliert wurde, und Ihr API-Schlüssel wird angegeben.
AndroidManifest.xml
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}" />
API-Schlüssel zu secrets.properties
hinzufügen
Öffnen Sie die Datei secrets.properties
im Verzeichnis der obersten Ebene und fügen Sie den folgenden Code ein. Ersetzen Sie dabei YOUR_API_KEY
durch Ihren eigenen API-Schlüssel.
MAPS_API_KEY=YOUR_API_KEY
Öffnen Sie die Datei local.defaults.properties
im Verzeichnis der obersten Ebene, im selben Ordner wie die Datei secrets.properties
, und fügen Sie folgenden Code ein.
MAPS_API_KEY=DEFAULT_API_KEY
Nach dem API-Schlüssel suchen
In onCreate()
wird der Maps API-Schlüssel geprüft und das Fragment für die Kartenunterstützung initialisiert. getMapAsync()
wird verwendet, um sich für den Karten-Callback zu registrieren.
Fügen Sie dazu den folgenden Code ein.
CurrentPlaceActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_current)
val apiKey = BuildConfig.MAPS_API_KEY
// Log an error if apiKey is not set.
if (apiKey.isEmpty() || apiKey == "DEFAULT_API_KEY") {
Log.e("Places test", "No api key")
finish()
return
}
// Retrieve a PlacesClient (previously initialized - see DemoApplication)
placesClient = Places.createClient(this)
(supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment?)?.getMapAsync(this)
// ...
}
Kartenlayout erstellen
- Erstellen Sie im Ordner
app/src/main/res/layout/
die Layoutdateifragment_map.xml
und fügen Sie den folgenden Code in das Layout ein.
res/layout/fragment_map.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.google.codelabs.maps.placesdemo.CurrentPlaceActivity" />
Damit wird ein SupportMapFragment
definiert, das als Container für die Karte fungiert und Zugriff auf das GoogleMap
-Objekt bietet.
- Fügen Sie im
activity_current.xml
-Layout, das im Ordnerapp/src/main/res/layout/
verfügbar ist, den folgenden Code am Ende des linearen Layouts hinzu.
res/layout/activity_current.xml
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:text="@string/showing_most_likely_place"
style="@style/TextAppearance.AppCompat.Title"/>
<include layout="@layout/fragment_map"/>
Die hinzugefügte TextView
verweist auf eine neue String-Ressource, die erstellt werden muss.
- Fügen Sie in
app/src/main/res/values/strings.xml
die folgende String-Ressource hinzu.
res/values/strings.xml
<string name="showing_most_likely_place">Showing most likely place</string>
Da der Karte zusätzliche Ansichten hinzugefügt wurden, muss die Höhe des TextView
, in dem die Liste der Orte angezeigt wird, so festgelegt werden, dass diese Ansichten sichtbar bleiben.
- Fügen Sie das Attribut
maxHeight
demTextView
mit der IDcurrent_response_content
hinzu.
res/layout/activity_current.xml
android:maxHeight="200dp"
OnMapReadyCallback
implementieren
Implementieren Sie die OnMapReadyCallback
-Schnittstelle, indem Sie sie der Klassendeklaration hinzufügen, und überschreiben Sie die onMapReady()
-Methode, um die Karte einzurichten, wenn das GoogleMap
-Objekt verfügbar ist:
CurrentPlaceActivity.kt
class CurrentPlaceActivity : AppCompatActivity(), OnMapReadyCallback {
Fügen Sie am Ende der Klasse den folgenden Code hinzu:
CurrentPlaceActivity.kt
override fun onMapReady(map: GoogleMap) {
this.map = map
lastKnownLocation?.let { location ->
map.moveCamera(
CameraUpdateFactory.newLatLngZoom(
location,
DEFAULT_ZOOM
)
)
}
}
Für den Callback sind einige Klassenvariablen erforderlich, damit er richtig funktioniert. Fügen Sie direkt nach dem Klassenheader Folgendes hinzu:
CurrentPlaceActivity.kt
private var map: GoogleMap? = null
private var lastKnownLocation: LatLng? = null
Fügen Sie dem Companion-Objekt der Klasse den folgenden Code hinzu:
CurrentPlaceActivity.kt
private const val DEFAULT_ZOOM = 15f
Anwendung ausführen
- Starten Sie die App.
- Tippen Sie auf die Zeile „Aktueller Ort“. Auf dem Bildschirm sollte eine Schaltfläche angezeigt werden.
- Tippe auf die Schaltfläche. Wenn Sie dieser App noch keine Berechtigung zur Standortermittlung erteilt haben, sollte eine Berechtigungsanfrage angezeigt werden.
- Erteilen Sie der App die Berechtigung, auf den Standort des Geräts zuzugreifen.
- Tippen Sie noch einmal auf die Schaltfläche. Die Karte wird angezeigt.
Abbildung 6: Aktivität „Aktueller Ort“ mit Karte.
Karte mit einem Ort aktualisieren
Fügen Sie am Ende der Klasse den folgenden Code hinzu:
CurrentPlaceActivity.kt
private data class LikelyPlace(
val name: String,
val address: String,
val attribution: List<String>,
val latLng: LatLng
)
private fun PlaceLikelihood.toLikelyPlace(): LikelyPlace? {
val name = this.place.name
val address = this.place.address
val latLng = this.place.latLng
val attributions = this.place.attributions ?: emptyList()
return if (name != null && address != null && latLng != null) {
LikelyPlace(name, address, attributions, latLng)
} else {
null
}
}
Sie werden verwendet, um die Daten des Orts zu speichern und zu formatieren.
Fügen Sie am Anfang der Klasse den folgenden Code hinzu, um eine Variable zum Speichern der zurückgegebenen Ortsdaten zu erstellen.
CurrentPlaceActivity.kt
private val likelyPlaces = mutableListOf<LikelyPlace>()
In diesem Schritt wird der Code so geändert, dass dem Nutzer eine Liste mit Orten angezeigt wird und er einen Ort auswählt, der auf der Karte angezeigt werden soll. Alle Daten zu Orten werden in einer Liste auf dem Bildschirm angezeigt.
In der Funktion findCurrentPlace
im Block lifecycleScope.launch
vor dieser Codezeile
CurrentPlaceActivity.kt
responseView.text = response.prettyPrint()
Fügen Sie den folgenden Code hinzu:
CurrentPlaceActivity.kt
likelyPlaces.clear()
likelyPlaces.addAll(
response.placeLikelihoods.take(M_MAX_ENTRIES).mapNotNull { placeLikelihood ->
placeLikelihood.toLikelyPlace()
}
)
openPlacesDialog()
Für diesen Code ist eine Konstante für die maximale Anzahl der anzuzeigenden Orte erforderlich.
Fügen Sie dem Companion-Objekt den Code für diese Konstante hinzu.
CurrentPlaceActivity.kt
private const val M_MAX_ENTRIES = 5
Fügen Sie den folgenden Code hinzu, um das Dialogfeld zu erstellen, in dem der Nutzer einen Ort auswählen kann.
CurrentPlaceActivity.kt
/**
* Displays a form allowing the user to select a place from a list of likely places.
*/
private fun openPlacesDialog() {
// Ask the user to choose the place where they are now.
val listener =
DialogInterface.OnClickListener { _, which -> // The "which" argument contains the position of the selected item.
val likelyPlace = likelyPlaces[which]
lastKnownLocation = likelyPlace.latLng
val snippet = buildString {
append(likelyPlace.address)
if (likelyPlace.attribution.isNotEmpty()) {
append("\n")
append(likelyPlace.attribution.joinToString(", "))
}
}
val place = Place.builder().apply {
name = likelyPlace.name
latLng = likelyPlace.latLng
}.build()
map?.clear()
setPlaceOnMap(place, snippet)
}
// Display the dialog.
AlertDialog.Builder(this)
.setTitle(R.string.pick_place)
.setItems(likelyPlaces.map { it.name }.toTypedArray(), listener)
.setOnDismissListener {
currentButton.isEnabled = true
}
.show()
}
Gemäß den Android-Best Practices verweist der Dialog auf eine String-Ressource, die der Ressourcendatei strings.xml
im Ordner app/src/main/res/values/
hinzugefügt werden muss.
Fügen Sie strings.xml
Folgendes hinzu:
res/values/strings.xml
<string name="pick_place">Choose a place</string>
Diese Funktionen rufen dann die Funktion setPlaceOnMap
auf, mit der die Kamera bewegt und eine Markierung am ausgewählten Ort platziert wird.
Fügen Sie den folgenden Code hinzu:
CurrentPlaceActivity.kt
private fun setPlaceOnMap(place: Place?, markerSnippet: String?) {
val latLng = place?.latLng ?: defaultLocation
map?.moveCamera(
CameraUpdateFactory.newLatLngZoom(
latLng,
DEFAULT_ZOOM
)
)
map?.addMarker(
MarkerOptions()
.position(latLng)
.title(place?.name)
.snippet(markerSnippet)
)
}
Es wird außerdem empfohlen, den Kartenstatus zu speichern und wiederherzustellen.
Überschreiben Sie die Funktion onSaveInstanceState
und fügen Sie den folgenden Code hinzu, um den Status zu speichern:
CurrentPlaceActivity.kt
/**
* Saves the state of the map when the activity is paused.
*/
override fun onSaveInstanceState(outState: Bundle) {
outState.putParcelable(KEY_LOCATION, lastKnownLocation)
super.onSaveInstanceState(outState)
}
Um den Zustand wiederherzustellen, fügen Sie in onCreate
den folgenden Code nach dem Aufruf von setContentView
ein:
CurrentPlaceActivity.kt
if (savedInstanceState != null) {
lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION)
}
Zum Speichern und Wiederherstellen ist ein Schlüssel erforderlich. Dies ist eine Konstante aus dem Companion-Objekt.
Fügen Sie im Companion-Objektblock Folgendes hinzu:
CurrentPlaceActivity.kt
// Key for storing activity state.
private const val KEY_LOCATION = "location"
Anwendung ausführen
- Starten Sie die App.
- Tippen Sie auf die Zeile „Aktueller Ort“. Auf dem Bildschirm sollte eine Schaltfläche angezeigt werden.
- Tippe auf die Schaltfläche. Wenn Sie dieser App noch keine Berechtigung zur Standortermittlung erteilt haben, sollte eine Berechtigungsanfrage angezeigt werden.
- Erteilen Sie der App die Berechtigung, auf den Standort des Geräts zuzugreifen.
- Tippen Sie noch einmal auf die Schaltfläche.
- Wählen Sie einen Ort aus, indem Sie darauf tippen. Die Karte wird vergrößert und zentriert und am ausgewählten Ort wird eine Markierung platziert.
Abbildung 7: Karte mit Markierung am ausgewählten Ort
12. Glückwunsch
Sie haben erfolgreich eine Android-App mit dem Places SDK for Android erstellt.
Das haben Sie gelernt
- Installieren und Konfigurieren des Places SDK for Android
- Installieren von Kotlin-Erweiterungen für das Places SDK for Android.
- Ortsdetails werden geladen.
- Place Autocomplete wurde hinzugefügt.
- Aktueller Ort wird abgerufen.
Nächste Schritte
- Weitere Inspirationen finden Sie im
android-places-demos
GitHub-Repository mit Beispielen und Demos. Sie können es auch forken. - Weitere Kotlin-Codelabs für die Entwicklung von Android-Apps mit der Google Maps Platform
- Helfen Sie uns, die Inhalte zu erstellen, die für Sie am nützlichsten sind, indem Sie die folgende Frage beantworten:
Welche anderen Codelabs würden Sie sich wünschen?
Ist das gewünschte Codelab nicht aufgeführt? Hier können Sie sie mit einem neuen Problem anfordern.