Tworzenie własnego selektora Aktualnego miejsca na Androida (Java)

1. Zanim zaczniesz

Dowiedz się, jak za pomocą Google Maps Platform i pakietu SDK Miejsc na Androida wyświetlać użytkownikom listę miejsc, aby mogli określić swoją bieżącą lokalizację.

bd07a9ad2cb27a06.png

Wymagania wstępne

  • podstawowe umiejętności w zakresie Javy,

Jakie zadania wykonasz

  • Dodaj mapę do aplikacji na Androida.
  • Używaj uprawnień do lokalizacji, aby określać lokalizację geograficzną użytkownika.
  • Pobieranie miejsc w pobliżu bieżącej lokalizacji użytkownika.
  • Wyświetlaj użytkownikowi prawdopodobne miejsca, aby mógł określić swoją bieżącą lokalizację.

Co utworzysz

Aplikację na Androida tworzysz od zera, ale podczas debugowania możesz pobrać kod przykładowy, aby go porównać. Pobierz przykładowy kod z GitHuba lub, jeśli masz skonfigurowany Git do używania w wierszu poleceń, wpisz to polecenie:

git clone https://github.com/googlecodelabs/current-place-picker-android.git

Jeśli podczas wykonywania tego laboratorium napotkasz jakiekolwiek problemy (błędy w kodzie, błędy gramatyczne, niejasne sformułowania lub inne), zgłoś je, klikając link Zgłoś błąd w lewym dolnym rogu laboratorium.

2. Rozpocznij

Zanim zaczniesz wykonywać zadania z tego ćwiczenia, musisz skonfigurować te elementy:

Android Studio

Pobierz Android Studio ze strony https://developer.android.com/studio.

Jeśli masz już Android Studio, sprawdź, czy korzystasz z najnowszej wersji. W tym celu kliknij Android Studio > Sprawdź dostępność aktualizacji….

1f36bae83b64e33.png

Te ćwiczenia zostały opracowane w Androidzie Studio 3.4.

Android SDK

W Android Studio możesz skonfigurować wybrane pakiety SDK za pomocą Menedżera SDK. W tym module używamy pakietu Android Q SDK.

  1. Na ekranie powitalnym Android Studio kliknij Configure (Skonfiguruj) > SDK Manager (Menedżer pakietów SDK).

d3fa03c269ec231c.png

  1. Zaznacz pole wyboru odpowiedniego pakietu SDK, a potem kliknij Zastosuj.

Jeśli nie masz jeszcze pakietu SDK, rozpocznie się jego pobieranie na Twój komputer.

884e0aa1314f70d.png

Usługi Google Play

W Menedżerze pakietów SDK musisz też zainstalować Usługi Google Play.

  1. Kliknij kartę Narzędzia SDK i zaznacz pole wyboru Usługi Google Play.

Zaktualizuj, jeśli stan to Dostępna aktualizacja.

ad6211fd78f3b629.png

3. Przygotowywanie emulatora

Aby uruchomić aplikację, możesz podłączyć własne urządzenie lub użyć emulatora Androida.

Jeśli używasz własnego urządzenia, przejdź do sekcji Instrukcje dotyczące prawdziwego urządzenia: aktualizowanie Usług Google Play na końcu tej strony.

Dodawanie emulatora

  1. Na ekranie powitalnym Android Studio kliknij Configure (Skonfiguruj) > AVD Manager (Menedżer AVD).

5dd2d14c9c56d3f9.png

Otworzy się okno Android Virtual Device Manager (Menedżer wirtualnych urządzeń z Androidem).

  1. Kliknij Utwórz urządzenie wirtualne…, aby otworzyć listę urządzeń, z której możesz wybrać urządzenie.

2d44eada384f8b35.png

  1. Wybierz urządzenie z ikoną Play d5722488d80cd6be.png w kolumnie Sklep Play i kliknij Dalej.

e0248f1c6e85ab7c.png

Zobaczysz zestaw obrazów systemu, które możesz zainstalować. Jeśli obok kierowania Q na Androida 9.+ (Google Play) znajduje się słowo Pobierz, kliknij Pobierz.

316d0d1efabd9f24.png

  1. Kliknij Dalej, aby nadać urządzeniu wirtualnemu nazwę, a potem kliknij Zakończ.

Wrócisz do listy Twoje urządzenia wirtualne.

  1. Kliknij Rozpocznij ba8adffe56d3b678.png obok nowego urządzenia:

7605864ed27f77ea.png

Po chwili otworzy się emulator.

Instrukcje dotyczące emulatora – aktualizacja Usług Google Play

  1. Po uruchomieniu emulatora kliknij na pasku nawigacyjnym, który się pojawi**.**

2e1156e02643d018.png

Otworzy się okno Rozszerzone elementy sterujące.

  1. W menu kliknij Google Play.

Jeśli aktualizacja jest dostępna, kliknij Aktualizuj.

5afd2686c5cad0e5.png

  1. Zaloguj się w emulatorze za pomocą konta Google.

Możesz użyć własnego konta lub utworzyć nowe bezpłatne konto, aby oddzielić testy od informacji osobistych.

Otworzy się Sklep Google Play z Usługami Google Play.

  1. Kliknij Aktualizuj, aby pobrać najnowszą wersję Usług Google Play.

f4bc067e80630b9c.png

Jeśli pojawi się prośba o dokończenie konfigurowania konta i dodanie opcji płatności, kliknij Pomiń.

Ustawianie lokalizacji w emulatorze

  1. Po uruchomieniu emulatora wpisz „mapy” na pasku wyszukiwania na ekranie głównym, aby wyświetlić ikonę aplikacji Mapy Google.

2d996aadd53685a6.png

  1. Kliknij ikonę, aby uruchomić aplikację.

Zobaczysz domyślną mapę.

  1. W prawym dolnym rogu mapy kliknij Twoja lokalizacja c5b4e2fda57a7e71.png.

Pojawi się prośba o przyznanie telefonowi uprawnień do korzystania z lokalizacji.

f2b68044eabca151.png

  1. Kliknij , aby otworzyć menu Rozszerzone opcje.
  2. Kliknij kartę Lokalizacja.
  3. Wpisz szerokość i długość geograficzną.

Wpisz dowolne miejsce, ale upewnij się, że w jego pobliżu jest wiele innych miejsc.

(Aby odtworzyć wyniki z tego laboratorium, użyj szerokości geograficznej 20,7818 i długości geograficznej -156,4624 dla miasta Kihei na wyspie Maui na Hawajach).

  1. Kliknij Wyślij, a mapa zostanie zaktualizowana o tę lokalizację.

f9576b35218f4187.png

Możesz teraz uruchomić aplikację i przetestować ją z lokalizacją.

Instrukcje dotyczące prawdziwego urządzenia – aktualizacja Usług Google Play

Jeśli używasz prawdziwego urządzenia z Androidem, wykonaj te czynności:

  1. Na pasku wyszukiwania na ekranie głównym wyszukaj i otwórz Usługi Google Play.
  2. Kliknij Więcej szczegółów.

Jeśli jest dostępna, kliknij Aktualizuj.

ad16cdb975b5c3f7.png baf0379ef8a9c88c.png

4. Tworzenie szkieletu aplikacji z aktywnością Map Google

  1. Na ekranie powitalnym Android Studio kliknij Start a new Android Studio project (Rozpocznij nowy projekt w Android Studio).
  2. Na karcie Telefon i tablet wybierz Aktywność w Mapach Google.

c9c80aa8211a8761.png

Otworzy się okno Skonfiguruj projekt. W tym miejscu możesz nazwać aplikację i utworzyć pakiet na podstawie domeny.

Oto ustawienia aplikacji o nazwie Current Place, która odpowiada pakietowi com.google.codelab.currentplace.

37f5b93b94ee118c.png

  1. Wybierz język Java i kliknij Use androidx. artifacts* (Użyj artefaktów androidx).

W pozostałych ustawieniach zachowaj wartości domyślne.

  1. Kliknij Zakończ.

5. Dodawanie zależności Usług Google do pliku kompilacji Gradle

Aby uzyskać dostęp do uprawnień związanych z lokalizacją na urządzeniach z Androidem, musisz mieć interfejs Google Location and Activity Recognition API z Usług Google Play. Więcej informacji o dodawaniu tego i innych interfejsów API Usług Google Play znajdziesz w artykule Konfigurowanie Usług Google Play.

Projekty Android Studio mają zwykle 2 pliki build.gradle. Jeden dotyczy całego projektu, a drugi – aplikacji. Jeśli w Android Studio masz otwarty eksplorator projektu w widoku Android, oba pliki zobaczysz w folderze Gradle Scripts. Aby dodać usługi Google, musisz edytować plik build.gradle (Module: app).

f3043429cf719c47.png

  1. Dodaj 2 wiersze do sekcji dependencies, aby dodać usługi Google do określania lokalizacji i interfejs Places API ( przykładowy kod w kontekście).

build.gradle (Module: app)

plugins {
  id 'com.android.application'
}

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.google.codelab.currentplace"
        minSdkVersion 19
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'com.google.android.gms:play-services-maps:16.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'

    implementation 'com.google.android.gms:play-services-location:16.0.0'
    implementation 'com.google.android.libraries.places:places:1.1.0'
}

6. Włączanie interfejsów API Google Maps Platform i uzyskiwanie klucza interfejsu API

Aby wykonać następny krok , musisz włączyć Maps SDK na AndroidaPlaces API.

Konfigurowanie Google Maps Platform

Jeśli nie masz jeszcze konta Google Cloud Platform i projektu z włączonymi płatnościami, zapoznaj się z przewodnikiem Pierwsze kroki z Google Maps Platform, aby utworzyć konto rozliczeniowe i projekt.

  1. W konsoli Google Cloud kliknij menu projektu i wybierz projekt, którego chcesz użyć w tym samouczku.

  1. Włącz interfejsy API i pakiety SDK Google Maps Platform wymagane w tym samouczku w Google Cloud Marketplace. Aby to zrobić, wykonaj czynności opisane w tym filmie lub tej dokumentacji.
  2. Wygeneruj klucz interfejsu API na stronie Dane logowania w konsoli Cloud. Możesz wykonać czynności opisane w tym filmie lub tej dokumentacji. Wszystkie żądania wysyłane do Google Maps Platform wymagają klucza interfejsu API.

Skopiuj utworzony klucz interfejsu API. Wróć do Android Studio i znajdź plik google_maps_api.xml w sekcji Android > app > res > values.

Zastąp YOUR_KEY_HERE skopiowanym kluczem interfejsu API.

aa576e551a7a1009.png

Aplikacja została skonfigurowana.

7. Edytowanie pliku układu

  1. W eksploratorze projektu otwórz plik activity_maps.xml w folderze Android > app > res > layout.

4e0d986480c57efa.png

  1. Po prawej stronie ekranu otworzy się podstawowy interfejs z kartami u dołu, które umożliwiają wybór edytora projektu lub tekstu. Kliknij Tekst i zastąp całą zawartość pliku układu tym kodem:

activity_maps.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:minHeight="?attr/actionBarSize"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:titleTextColor="@android:color/white"
        android:background="@color/colorPrimary" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <fragment
            android:id="@+id/map"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="349dp"
            tools:context=".MapsActivity" />

        <ListView
            android:id="@+id/listPlaces"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

Interfejs użytkownika będzie wyglądać tak:

1bf786808a4697ce.png

8. Konfigurowanie paska aplikacji

Aby dać użytkownikowi przycisk, który może kliknąć, gdy chce wybrać bieżące miejsce, dodaj pasek aplikacji z ikoną, która wyszukuje bieżące miejsce użytkownika i wyświetla pobliskie prawdopodobne miejsca. Będzie on wyglądał :

3a17c92b613a26c5.png

Na telefonie wyświetla się tylko ikona. Na tablecie z większą ilością miejsca tekst jest również uwzględniony.

Tworzenie ikony

  1. W eksploratorze projektu kliknij Android > app, a następnie kliknij prawym przyciskiem myszy folder res i wybierz New (Nowy) > Image Asset (Zasób obrazu).

Otworzy się Asset Studio.

  1. W menu Typ ikony kliknij Ikony paska działań i kart.
  2. Nazwij komponent ic_geolocate.
  3. Jako typ zasobu wybierz Clip Art**.**
  4. Kliknij grafikę obok opcji Clip Art (Klipart).

Otworzy się okno Wybierz ikonę.

  1. Wybierz ikonę.

Za pomocą paska wyszukiwania możesz znaleźć ikony związane z Twoim zamiarem.

  1. Wyszukaj location i wybierz ikonę związaną z lokalizacją.

Ikona mojej lokalizacji jest taka sama jak w aplikacji Mapy Google, gdy użytkownik chce skierować aparat na swoją bieżącą lokalizację.

  1. Kliknij OK > Dalej > Zakończ i sprawdź, czy jest nowy folder o nazwie drawable, który zawiera nowe pliki ikon.

b9e0196137ed18ae.png

Dodawanie zasobów w postaci ciągów znaków

  1. W eksploratorze projektu kliknij Android > app > res > values i otwórz plik strings.xml.
  2. Po <string name="title_activity_maps">Map</string> dodaj te wiersze:

strings.xml

    <string name="action_geolocate">Pick Place</string>
    <string name="default_info_title">Default Location</string>
    <string name="default_info_snippet">No places found, because location permission is disabled.</string>

Pierwszy wiersz jest używany na pasku aplikacji, gdy jest miejsce na umieszczenie etykiety tekstowej obok ikony. Pozostałe są używane w przypadku znaczników dodawanych do mapy.

Teraz kod w pliku wygląda tak:

<resources>
    <string name="app_name">Current Place</string>
    <string name="title_activity_maps">Map</string>
    <string name="action_geolocate">Pick Place</string>
    <string name="default_info_title">Default Location</string>
    <string name="default_info_snippet">No places found, because location permission is disabled.</string>
</resources>

Dodawanie paska aplikacji

  1. W eksploratorze projektu kliknij Android > app, a następnie kliknij prawym przyciskiem myszy folder res i wybierz Nowy > Katalog, aby utworzyć nowy podkatalog w app/src/main/res.
  2. Nazwij katalog menu.
  3. Kliknij prawym przyciskiem myszy folder menu i wybierz Nowy > Plik.
  4. Nadaj plikowi nazwę menu.xml.
  5. Wklej ten kod:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <!-- "Locate me", should appear as action button if possible -->
    <item
        android:id="@+id/action_geolocate"
        android:icon="@drawable/ic_geolocate"
        android:title="@string/action_geolocate"
        app:showAsAction="always|withText" />

</menu>

Aktualizowanie stylu paska aplikacji

  1. W eksploratorze projektu rozwiń kolejno Android > app > res > values i otwórz plik styles.xml.
  2. W tagu <style> zmień właściwość elementu nadrzędnego na "Theme.AppCompat.NoActionBar".
  3. Zanotuj właściwość name, której użyjesz w następnym kroku.

styles.xml

<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">

Aktualizowanie motywu aplikacji w pliku AndroidManifest.xml

  1. Kliknij Androidappmanifests i otwórz plik AndroidManifest.xml.
  2. Znajdź wiersz android:theme i zmień lub potwierdź wartość @style/AppTheme.

AndroidManifest.xml

   <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

Możesz już zacząć pisać kod.

9. Inicjowanie aplikacji

  1. W eksploratorze projektu znajdź plik MapsActivity.java.

Znajduje się on w folderze odpowiadającym pakietowi utworzonemu w kroku 1.

8b0fa27d417f5f55.png

  1. Otwórz plik, a zostanie wyświetlony edytor kodu Java.

Zaimportuj pakiet SDK Miejsc i inne zależności

Dodaj te wiersze na początku pliku MapsActivity.java, zastępując istniejące instrukcje importu.

Obejmują one istniejące importy i dodają wiele innych używanych w kodzie w tym laboratorium.

MapsActivity.java

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.libraries.places.api.Places;
import com.google.android.libraries.places.api.model.Place;
import com.google.android.libraries.places.api.model.PlaceLikelihood;
import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest;
import com.google.android.libraries.places.api.net.FindCurrentPlaceResponse;
import com.google.android.libraries.places.api.net.PlacesClient;

import java.util.Arrays;
import java.util.List;

Aktualizowanie podpisu zajęć

Interfejs Places API używa komponentów AndroidX, aby zapewnić zgodność wsteczną, więc musisz zdefiniować go tak, aby rozszerzał AppCompatActivity. Zastępuje rozszerzenie FragmentActivity, które jest domyślnie zdefiniowane dla aktywności związanej z mapami.

public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {

Dodawanie zmiennych zajęć

Następnie zadeklaruj różne zmienne klasy używane w różnych metodach klasy. Obejmują one elementy interfejsu i kody stanu. Powinny się one znajdować tuż pod deklaracją zmiennej GoogleMap mMap.

    // New variables for Current Place picker
    private static final String TAG = "MapsActivity";
    ListView lstPlaces;
    private PlacesClient mPlacesClient;
    private FusedLocationProviderClient mFusedLocationProviderClient;

    // The geographical location where the device is currently located. That is, the last-known
    // location retrieved by the Fused Location Provider.
    private Location mLastKnownLocation;

    // A default location (Sydney, Australia) and default zoom to use when location permission is
    // not granted.
    private final LatLng mDefaultLocation = new LatLng(-33.8523341, 151.2106085);
    private static final int DEFAULT_ZOOM = 15;
    private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
    private boolean mLocationPermissionGranted;

    // Used for selecting the Current Place.
    private static final int M_MAX_ENTRIES = 5;
    private String[] mLikelyPlaceNames;
    private String[] mLikelyPlaceAddresses;
    private String[] mLikelyPlaceAttributions;
    private LatLng[] mLikelyPlaceLatLngs;

Zaktualizuj metodę onCreate

Musisz zaktualizować metodę onCreate, aby obsługiwała uprawnienia użytkownika w czasie działania aplikacji w zakresie usług lokalizacyjnych, konfigurowała elementy interfejsu i tworzyła klienta interfejsu Places API.

Dodaj te wiersze kodu dotyczące paska narzędzi działania, konfiguracji widoków i klienta Places na końcu istniejącej metody onCreate().

MapsActivity.java onCreate()

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);

        //
        // PASTE THE LINES BELOW THIS COMMENT
        //
        
        // Set up the action toolbar
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        // Set up the views
        lstPlaces = (ListView) findViewById(R.id.listPlaces);

        // Initialize the Places client
        String apiKey = getString(R.string.google_maps_key);
        Places.initialize(getApplicationContext(), apiKey);
        mPlacesClient = Places.createClient(this);
        mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
    }

Dodawanie kodu menu paska aplikacji

Te 2 metody dodają menu paska aplikacji (z 1 elementem, ikoną Wybierz miejsce) i obsługują kliknięcie ikony przez użytkownika.

Skopiuj te 2 metody do pliku po metodzie onCreate.

MapsActivity.java onCreateOptionsMenu() i onOptionsItemSelected()

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
           case R.id.action_geolocate:
                
                // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                // Present the current place picker
                // pickCurrentPlace();
                return true;

            default:
                // If we got here, the user's action was not recognized.
                // Invoke the superclass to handle it.
                return super.onOptionsItemSelected(item);

        }
    }

Przetestuj

  1. W Android Studio kliknij Uruchom lub Menu Uruchom > Uruchom „aplikację”.

28bea91c68c36fb2.png

  1. Zobaczysz prośbę o wybranie miejsca wdrożenia. Na tej liście powinien się pojawić uruchomiony emulator. Wybierz go, a Android Studio wdroży aplikację w emulatorze.

f44658ca91f6f41a.png

Po chwili aplikacja się uruchomi. Wyświetli się mapa wyśrodkowana na Sydney w Australii z jednym przyciskiem i pustą listą miejsc.

68eb8c70f4748350.png

Środek mapy nie przesuwa się do lokalizacji użytkownika, chyba że poprosisz o uprawnienia dostępu do lokalizacji urządzenia.

10. Wysyłanie prośby o dostęp do lokalizacji i obsługa tego dostępu

Wysyłanie prośby o dostęp do lokalizacji po przygotowaniu mapy

  1. Zdefiniuj metodę o nazwie getLocationPermission, która prosi użytkownika o uprawnienia.

Wklej ten kod pod utworzoną przed chwilą metodą onOptionsSelected.

MapsActivity.java getLocationPermission()

    private void getLocationPermission() {
        /*
         * Request location permission, so that we can get the location of the
         * device. The result of the permission request is handled by a callback,
         * onRequestPermissionsResult.
         */
        mLocationPermissionGranted = false;
        if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
                android.Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            mLocationPermissionGranted = true;
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
                    PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
        }
    }
  1. Dodaj 2 wiersze na końcu istniejącej metody onMapReady, aby włączyć elementy sterujące powiększeniem i poprosić użytkownika o uprawnienia do lokalizacji.

MapsActivity.java onMapReady()

   @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;

        // Add a marker in Sydney and move the camera
        LatLng sydney = new LatLng(-34, 151);
        mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
        mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));

        //
        // PASTE THE LINES BELOW THIS COMMENT
        //

        // Enable the zoom controls for the map
        mMap.getUiSettings().setZoomControlsEnabled(true);

        // Prompt the user for permission.
        getLocationPermission();

    }

Obsługa wyniku prośby o uprawnienia

Gdy użytkownik odpowie na okno z prośbą o przyznanie uprawnień, Android wywoła to wywołanie zwrotne.

Wklej ten kod po metodzie getLocationPermission():

MapsActivity.java onRequestPermissionsResult()

   /**
     * Handles the result of the request for location permissions
     */
    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String permissions[],
                                           @NonNull int[] grantResults) {
        mLocationPermissionGranted = false;
        switch (requestCode) {
            case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    mLocationPermissionGranted = true;
                }
            }
        }
    }

11. Pobieranie bieżącej lokalizacji i pobieranie prawdopodobnych miejsc

Gdy użytkownik kliknie Wybierz miejsce na pasku aplikacji, aplikacja wywoła metodę pickCurrentPlace(), która wywoła zdefiniowaną wcześniej metodę getDeviceLocation(). Metoda getDeviceLocation wywołuje inną metodę, getCurrentPlaceLikelihoods,, po pobraniu najnowszej lokalizacji urządzenia.

Wywołaj interfejs API findCurrentPlace i obsłuż odpowiedź

getCurrentPlaceLikelihoods tworzy findCurrentPlaceRequest i wywołuje zadanie Places API findCurrentPlace. Jeśli zadanie się powiedzie, zwraca obiekt findCurrentPlaceResponse, który zawiera listę obiektów placeLikelihood. Każda z nich ma wiele właściwości, w tym nazwę i adres miejsca oraz prawdopodobieństwo, że się w nim znajdujesz (wartość zmiennoprzecinkowa od 0 do 1). Ta metoda obsługuje odpowiedź, tworząc listy szczegółów miejsca z placeLikelihoods.

Ten kod iteruje po 5 najbardziej prawdopodobnych miejscach i dodaje do listy te, których prawdopodobieństwo jest większe niż 0. Następnie renderuje tę listę. Jeśli chcesz wyświetlać więcej lub mniej niż 5 elementów, zmień stałą M_MAX_ENTRIES.

Wklej ten kod po metodzie onMapReady.

MapsActivity.java getCurrentPlaceLikelihoods()

   private void getCurrentPlaceLikelihoods() {
        // Use fields to define the data types to return.
        List<Place.Field> placeFields = Arrays.asList(Place.Field.NAME, Place.Field.ADDRESS,
                Place.Field.LAT_LNG);

        // Get the likely places - that is, the businesses and other points of interest that
        // are the best match for the device's current location.
        @SuppressWarnings("MissingPermission") final FindCurrentPlaceRequest request =
                FindCurrentPlaceRequest.builder(placeFields).build();
        Task<FindCurrentPlaceResponse> placeResponse = mPlacesClient.findCurrentPlace(request);
        placeResponse.addOnCompleteListener(this,
                new OnCompleteListener<FindCurrentPlaceResponse>() {
                    @Override
                    public void onComplete(@NonNull Task<FindCurrentPlaceResponse> task) {
                        if (task.isSuccessful()) {
                            FindCurrentPlaceResponse response = task.getResult();
                            // Set the count, handling cases where less than 5 entries are returned.
                            int count;
                            if (response.getPlaceLikelihoods().size() < M_MAX_ENTRIES) {
                                count = response.getPlaceLikelihoods().size();
                            } else {
                                count = M_MAX_ENTRIES;
                            }

                            int i = 0;
                            mLikelyPlaceNames = new String[count];
                            mLikelyPlaceAddresses = new String[count];
                            mLikelyPlaceAttributions = new String[count];
                            mLikelyPlaceLatLngs = new LatLng[count];

                            for (PlaceLikelihood placeLikelihood : response.getPlaceLikelihoods()) {
                                Place currPlace = placeLikelihood.getPlace();
                                mLikelyPlaceNames[i] = currPlace.getName();
                                mLikelyPlaceAddresses[i] = currPlace.getAddress();
                                mLikelyPlaceAttributions[i] = (currPlace.getAttributions() == null) ?
                                        null : TextUtils.join(" ", currPlace.getAttributions());
                                mLikelyPlaceLatLngs[i] = currPlace.getLatLng();

                                String currLatLng = (mLikelyPlaceLatLngs[i] == null) ?
                                        "" : mLikelyPlaceLatLngs[i].toString();

                                Log.i(TAG, String.format("Place " + currPlace.getName()
                                        + " has likelihood: " + placeLikelihood.getLikelihood()
                                        + " at " + currLatLng));

                                i++;
                                if (i > (count - 1)) {
                                    break;
                                }
                            }


                            // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                            // Populate the ListView
                            // fillPlacesList();
                        } else {
                            Exception exception = task.getException();
                            if (exception instanceof ApiException) {
                                ApiException apiException = (ApiException) exception;
                                Log.e(TAG, "Place not found: " + apiException.getStatusCode());
                            }
                        }
                    }
                });
    }

Przesuwanie kamery mapy do bieżącej lokalizacji urządzenia

Jeśli użytkownik przyzna uprawnienia, aplikacja pobierze jego najnowszą lokalizację i wyśrodkuje na niej widok kamery.

Jeśli użytkownik odmówi przyznania uprawnień, aplikacja po prostu przeniesie kamerę do domyślnej lokalizacji zdefiniowanej wśród stałych wartości na początku tej strony (w przykładowym kodzie jest to Sydney w Australii).

Wklej ten kod po metodzie getPlaceLikelihoods():

MapsActivity.java getDeviceLocation()

    private void getDeviceLocation() {
        /*
         * Get the best and most recent location of the device, which may be null in rare
         * cases when a location is not available.
         */
        try {
            if (mLocationPermissionGranted) {
                Task<Location> locationResult = mFusedLocationProviderClient.getLastLocation();
                locationResult.addOnCompleteListener(this, new OnCompleteListener<Location>() {
                    @Override
                    public void onComplete(@NonNull Task<Location> task) {
                        if (task.isSuccessful()) {
                            // Set the map's camera position to the current location of the device.
                            mLastKnownLocation = task.getResult();
                            Log.d(TAG, "Latitude: " + mLastKnownLocation.getLatitude());
                            Log.d(TAG, "Longitude: " + mLastKnownLocation.getLongitude());
                            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
                                    new LatLng(mLastKnownLocation.getLatitude(),
                                            mLastKnownLocation.getLongitude()), DEFAULT_ZOOM));
                        } else {
                            Log.d(TAG, "Current location is null. Using defaults.");
                            Log.e(TAG, "Exception: %s", task.getException());
                            mMap.moveCamera(CameraUpdateFactory
                                    .newLatLngZoom(mDefaultLocation, DEFAULT_ZOOM));
                        }

                       getCurrentPlaceLikelihoods();
                    }
                });
            }
        } catch (SecurityException e)  {
            Log.e("Exception: %s", e.getMessage());
        }
    }

Sprawdzanie uprawnień do lokalizacji, gdy użytkownik kliknie Wybierz miejsce

Gdy użytkownik kliknie Wybierz miejsce, ta metoda sprawdza uprawnienia do lokalizacji i wyświetla prośbę o przyznanie uprawnień, jeśli nie zostały one jeszcze przyznane.

Jeśli użytkownik przyznał uprawnienia, metoda wywołuje funkcję getDeviceLocation, aby rozpocząć proces pobierania bieżących prawdopodobnych miejsc.

  1. Dodaj tę metodę po getDeviceLocation():

MapsActivity.java pickCurrentPlace()

   private void pickCurrentPlace() {
        if (mMap == null) {
            return;
        }

        if (mLocationPermissionGranted) {
            getDeviceLocation();
        } else {
            // The user has not granted permission.
            Log.i(TAG, "The user did not grant location permission.");

            // Add a default marker, because the user hasn't selected a place.
            mMap.addMarker(new MarkerOptions()
                    .title(getString(R.string.default_info_title))
                    .position(mDefaultLocation)
                    .snippet(getString(R.string.default_info_snippet)));

            // Prompt the user for permission.
            getLocationPermission();
        }
    }
  1. Teraz, gdy zdefiniowano pickCurrentPlace, znajdź w onOptionsItemSelected() wiersz, który wywołuje pickCurrentPlace, i usuń z niego znacznik komentarza.

MapsActivity.java onOptionItemSelected()

           case R.id.action_geolocate:

                // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                // Present the Current Place picker
                pickCurrentPlace();
                return true;

Przetestuj

Jeśli teraz uruchomisz aplikację i klikniesz Wybierz miejsce, powinna ona poprosić o uprawnienia do lokalizacji.

  • Jeśli zezwolisz na dostęp, preferencja zostanie zapisana i nie pojawi się prośba o zezwolenie. Jeśli odmówisz, przy następnym kliknięciu przycisku pojawi się prośba o przyznanie uprawnień.
  • Chociaż getPlaceLikelihoods pobrał prawdopodobne bieżące miejsca, ListView jeszcze ich nie wyświetla. W Android Studio możesz kliknąć ⌘6, aby sprawdzić logi w Logcat pod kątem instrukcji oznaczonych tagiem MapsActivity i upewnić się, że nowe metody działają prawidłowo.
  • Jeśli udzielisz uprawnień, dzienniki będą zawierać oświadczenie dotyczące Latitude: i oświadczenie dotyczące Longitude:, w których będzie widoczna wykryta lokalizacja urządzenia. Jeśli wcześniej w Mapach Google i w rozszerzonym menu emulatora określono lokalizację emulatora, te instrukcje będą ją wyświetlać.
  • Jeśli wywołanie funkcji findCurrentPlace się powiedzie, dzienniki będą zawierać 5 instrukcji wyświetlających nazwy i lokalizacje 5 najbardziej prawdopodobnych miejsc.

d9896a245b81bf3.png

12. Wypełnianie selektora Aktualne miejsce

Konfigurowanie funkcji obsługi wybranych miejsc

Zastanówmy się, co ma się stać, gdy użytkownik kliknie element w ListView. Aby potwierdzić wybór użytkownika dotyczący miejsca, w którym się obecnie znajduje, możesz dodać do mapy znacznik w tym miejscu. Jeśli użytkownik kliknie ten znacznik, pojawi się okno informacyjne z nazwą i adresem miejsca.

Wklej ten moduł obsługi kliknięć po metodzie pickCurrentPlace.

MapsActivity.java listClickedHandler

    private AdapterView.OnItemClickListener listClickedHandler = new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView parent, View v, int position, long id) {
            // position will give us the index of which place was selected in the array
            LatLng markerLatLng = mLikelyPlaceLatLngs[position];
            String markerSnippet = mLikelyPlaceAddresses[position];
            if (mLikelyPlaceAttributions[position] != null) {
                markerSnippet = markerSnippet + "\n" + mLikelyPlaceAttributions[position];
            }

            // Add a marker for the selected place, with an info window
            // showing information about that place.
            mMap.addMarker(new MarkerOptions()
                    .title(mLikelyPlaceNames[position])
                    .position(markerLatLng)
                    .snippet(markerSnippet));

           // Position the map's camera at the location of the marker.
            mMap.moveCamera(CameraUpdateFactory.newLatLng(markerLatLng));
        }
    };

Wypełnianie widoku listy

Teraz, gdy masz już listę najbardziej prawdopodobnych miejsc, w których użytkownik obecnie przebywa, możesz wyświetlić te opcje w ListView. Możesz też ustawić ListView detektor kliknięć, aby używał zdefiniowanego przed chwilą modułu obsługi kliknięć.

Wklej tę metodę po funkcji obsługi kliknięć:

MapsActivity.java fillPlacesList()

    private void fillPlacesList() {
        // Set up an ArrayAdapter to convert likely places into TextViews to populate the ListView
        ArrayAdapter<String> placesAdapter =
                new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mLikelyPlaceNames);
        lstPlaces.setAdapter(placesAdapter);
        lstPlaces.setOnItemClickListener(listClickedHandler);
    }

Teraz, gdy zdefiniowano fillPlacesList, znajdź wiersz pod koniec findPlaceLikelihoods, który wywołuje fillPlacesList, i usuń z niego znacznik komentarza.

MapsActivity.java fillPlaceLikelihoods()

               // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                // Populate the ListView
                fillPlacesList();

To cały kod potrzebny do selektora bieżącego miejsca.

13. Uruchamianie aplikacji

Testowanie wyboru miejsca

  1. Uruchom ponownie aplikację.

Gdy tym razem klikniesz Wybierz miejsce, aplikacja wypełni listę nazwami miejsc w pobliżu. W pobliżu tego miejsca na Maui znajdują się m.in. Ululani's Hawaiian Shave Ice i Sugar Beach Bake Shop. Ponieważ kilka miejsc znajduje się bardzo blisko współrzędnych lokalizacji, jest to lista prawdopodobnych miejsc, w których możesz się znajdować.

  1. Kliknij nazwę miejsca w ListView.

Na mapie powinien pojawić się znacznik.

  1. Kliknij znacznik.

Możesz wyświetlić informacje o miejscu.

e52303cc0de6a513.png 864c74342fb52a01.png

Sprawdź inną lokalizację

Jeśli chcesz zmienić lokalizację i korzystasz z emulatora, lokalizacja urządzenia nie zaktualizuje się automatycznie po zaktualizowaniu współrzędnych lokalizacji w menu rozszerzonym emulatora.

Aby to obejść, wykonaj te czynności, aby użyć natywnej aplikacji Mapy Google do wymuszenia aktualizacji lokalizacji emulatora:

  1. Otwórz Mapy Google.
  2. Kliknij > Lokalizacja, aby zmienić szerokość i długość geograficzną na nowe współrzędne, a następnie kliknij Wyślij.
  3. Możesz na przykład użyć szerokości geograficznej 49.2768 i długości geograficznej -123.1142, aby ustawić lokalizację w centrum Vancouver w Kanadzie.
  4. Sprawdź, czy Mapy Google ponownie wyśrodkowały się na nowych współrzędnych. Aby poprosić o wyśrodkowanie, może być konieczne kliknięcie przycisku Moja lokalizacja w aplikacji Mapy Google.
  5. Wróć do aplikacji Current Place i kliknij Pick Place (Wybierz miejsce), aby wyświetlić mapę z nowymi współrzędnymi i nową listę prawdopodobnych bieżących lokalizacji.

9adb99d1ce25c184.png

To wszystko. Masz prostą aplikację, która sprawdza miejsca w bieżącej lokalizacji i określa prawdopodobieństwo, że w nich jesteś. Miłej zabawy!

Teraz uruchom aplikację ze wprowadzonymi zmianami, aby wykonać ten dodatkowy krok.

14. Dalsze kroki

Aby zapobiec kradzieży klucza interfejsu API, musisz go zabezpieczyć, aby tylko Twoja aplikacja na Androida mogła go używać. Jeśli nie ograniczysz klucza, każda osoba, która go ma, może używać go do wywoływania interfejsów API Google Maps Platform, co spowoduje naliczenie opłat.

Uzyskiwanie certyfikatu SHA-1

Będzie Ci on potrzebny później, gdy będziesz ograniczać klucze interfejsu API. Poniżej znajdziesz instrukcje uzyskiwania certyfikatu debugowania.

W systemie Linux lub macOS otwórz okno terminala i wpisz:

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android

W przypadku systemów Windows Vista i Windows 7 uruchom to polecenie:

keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android

Dane wyjściowe powinny być podobne do tych:

Alias name: androiddebugkey
Creation date: Jan 01, 2013
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=Android Debug, O=Android, C=US
Issuer: CN=Android Debug, O=Android, C=US
Serial number: 4aa9b300
Valid from: Mon Jan 01 08:04:04 UTC 2013 until: Mon Jan 01 18:04:04 PST 2033
Certificate fingerprints:
     MD5:  AE:9F:95:D0:A6:86:89:BC:A8:70:BA:34:FF:6A:AC:F9
     SHA1: BB:0D:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:75
     Signature algorithm name: SHA1withRSA
     Version: 3

Wiersz zaczynający się od SHA1 zawiera odcisk cyfrowy SHA-1 certyfikatu. Odcisk palca to ciąg 20 dwucyfrowych liczb szesnastkowych oddzielonych dwukropkami.

Gdy aplikacja będzie gotowa do opublikowania, postępuj zgodnie z instrukcjami w tej dokumentacji, aby pobrać certyfikat wersji.

Dodawanie ograniczeń do klucza interfejsu API

  1. W konsoli Cloud kliknij Interfejsy API i usługi > Dane logowania.

Klucz użyty w tej aplikacji powinien być widoczny w sekcji Klucze interfejsu API.

  1. Kliknij 6454a04865d551e6.png, aby edytować ustawienia klucza.

316b052c621ee91c.png

  1. Na stronie klucza interfejsu API w sekcji Ograniczenia klucza ustaw Ograniczenia aplikacji, wykonując te czynności:
  2. Kliknij Aplikacje na Androida i postępuj zgodnie z instrukcjami.
  3. Kliknij Dodaj element.
  4. Wpisz nazwę pakietu i odcisk cyfrowy certyfikatu SHA-1 (uzyskany w poprzedniej sekcji).

Na przykład:

com.google.codelab.currentplace
BB:0D:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:75s
  1. Aby zapewnić dodatkową ochronę, ustaw ograniczenia interfejsów API, wykonując te czynności:
  2. W sekcji Ograniczenia interfejsów API wybierz Ogranicz klucz.
  3. Wybierz Maps SDK na Androida i Places API.
  4. Kliknij kolejno GotoweZapisz.

15. Gratulacje

Utworzono prostą aplikację, która sprawdza najbardziej prawdopodobne miejsca w bieżącej lokalizacji i dodaje do mapy znacznik wybranego przez użytkownika miejsca.

Więcej informacji