Tworzenie własnego selektora bieżącego miejsca na Androida (Java)

1. Zanim zaczniesz

Dowiedz się, jak używać Google Maps Platform oraz pakietu Places SDK dla Androida do przedstawiania użytkownikom listy miejsc w celu identyfikowania ich aktualnych lokalizacji.

bd07a9ad2cb27a06.png

Wymagania wstępne

  • Podstawowe umiejętności dotyczące języka Java

Jakie zadania wykonasz:

  • Dodawanie mapy do aplikacji na Androida.
  • Użyj geolokalizacji, aby określić lokalizację użytkownika.
  • Pobierz miejsca w pobliżu bieżącej lokalizacji użytkownika.
  • Wyświetl użytkownikowi prawdopodobne miejsce, aby określić jego bieżącą lokalizację.

Co stworzysz

Aplikację na Androida tworzysz od zera, ale możesz pobrać przykładowy kod i porównać go przy debugowaniu. Pobierz przykładowy kod z GitHuba lub, jeśli masz skonfigurowane używanie Git w wierszu poleceń, wpisz to:

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

Jeśli podczas ćwiczeń z programowania napotkasz jakiekolwiek błędy (błędy w kodzie, błędy gramatyczne, niezrozumiałe słowa lub coś innego) zgłoś je, klikając link Zgłoś błąd w lewym dolnym rogu ćwiczeń z programowania.

2. Wypróbuj

Przed rozpoczęciem tych ćwiczeń musisz skonfigurować te elementy:

Android Studio,

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

Jeśli masz już aplikację Android Studio, upewnij się, że masz jej najnowszą wersję, klikając Android Studio > Sprawdź dostępność aktualizacji...

1f36bae83b64e33.png

Ten moduł został napisany w Android Studio 3.4.

Android SDK

W Android Studio możesz skonfigurować wybrane pakiety SDK za pomocą Menedżera pakietów. W tym module wykorzystano pakiet SDK Androida Q.

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

d3fa03c269ec231c.png

  1. Zaznacz pole wyboru pakietu SDK i kliknij Zastosuj.

Jeśli nie masz pakietu SDK, rozpocznie się pobieranie pakietu na komputer.

884e0aa1314f70d.png

Usługi Google Play

Z poziomu menedżera SDK musisz też zainstalować Usługi Google Play.

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

Zmień stan, jeśli wyświetli się komunikat Dostępna aktualizacja.

ad6211fd78f3b629.png

3. Przygotowywanie emulatora

Aby ją uruchomić, podłącz swoje urządzenie lub użyj emulatora Androida.

Jeśli korzystasz z własnego urządzenia, przejdź do sekcji Rzeczywiste instrukcje dotyczące urządzenia: aktualizowanie Usług Google Play na końcu tej strony.

Dodaj emulator

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

5dd2d14c9c56d3f9.png

Otworzy się okno Menedżer urządzeń wirtualnych z Androidem.

  1. Kliknij Utwórz urządzenie wirtualne..., aby otworzyć listę urządzeń do wyboru.

2d44eada384f8b35.png

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

e0248f1c6e85ab7c.png

Zobaczysz zestaw obrazów systemowych, które możesz zainstalować. Jeśli obok pozycji Q na pozycji Android 9.+ (Google Play) widać napis Pobierz, kliknij Pobierz.

316d0d1efabd9f24.png

  1. Kliknij Dalej, by nazwać urządzenie wirtualne, a potem kliknij Zakończ.

Wrócisz do listy Twoje urządzenia wirtualne.

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

7605864ed27f77ea.png

Po chwili uruchomi się emulator.

Instrukcje dotyczące emulatorów – aktualizowanie Usług Google Play

  1. Po uruchomieniu emulatora kliknij ... na wyświetlonym pasku nawigacyjnym****.

2e1156e02643d018.png

Otworzy się okno Rozszerzone elementy sterujące.

  1. Kliknij Google Play w menu.

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

5afd2686c5cad0e5.png

  1. Zaloguj się do emulatora za pomocą konta Google.

Możesz korzystać z własnego konta lub bezpłatnie utworzyć nowe konto, aby oddzielać testy od swoich danych osobowych.

Następnie Google Play otwiera się w Usługach Google Play.

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

F4BC067e80630b9c.png

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

Ustawianie lokalizacji w emulatorze

  1. Po uruchomieniu emulatora wpisz w pasku wyszukiwania na ekranie głównym &&tt;maps", aby wyświetlić ikonę aplikacji Mapy Google.

2d996aadd53685a6.png

  1. Kliknij ikonę, aby ją uruchomić.

Pojawi się mapa domyślna.

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

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

F2B68044Eabca151.png

  1. Kliknij ..., by otworzyć menu Rozszerzone elementy sterujące.
  2. Kliknij kartę Lokalizacja.
  3. Wpisz szerokość i długość geograficzną.

Możesz wpisać tu wszystko, co lubisz, ale pamiętaj, aby umieścić go w miejscu pełnym wielu miejsc.

(Użyj opcji Współrzędne 20.7818 i Długość geograficzna -156.4624 dla miasta Kihei na Hawajach, aby powielić wyniki ćwiczenia z programowania).

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

F9576B35218f4187.png

Wszystko jest gotowe do uruchomienia aplikacji i przetestowania jej z wykorzystaniem lokalizacji.

Rzeczywiste instrukcje dotyczące urządzeń – aktualizowanie Usług Google Play

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

  1. Użyj paska wyszukiwania na ekranie głównym, aby wyszukać i otworzyć Usługi Google Play.
  2. Kliknij Więcej szczegółów.

Kliknij Aktualizuj, jeśli jest dostępna.

ad16cdb975b5c3f7.png baf0379ef8a9c88c.png

4. Tworzenie powłoki aplikacji za pomocą aktywności w Mapach Google

  1. Na ekranie powitalnym Android Studio wybierz Rozpocznij nowy projekt Android Studio.
  2. Na karcie Telefon i tablet wybierz Aktywność w Mapach Google.

C9C80aa8211a8761.png

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

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

37f5b93b94ee118c.png

  1. Wybierz Java jako język i Użyj artefaktów androidx. *.

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

  1. Kliknij Zakończ.

5. Dodaj zależności Google Services do pliku kompilacji Gradle

Aby uzyskać dostęp do dostępu do lokalizacji na urządzeniu z Androidem, musisz mieć interfejs Google Location and Activity Recognition API firmy Usługi 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 dwa pliki build.gradle. Jeden jest przeznaczony do całego projektu, a drugi dotyczy aplikacji. Jeśli w widoku Androida masz eksplorator projektów Android Studio, oba zobaczysz w folderze Gradle Scripts. Musisz edytować plik build.gradle (Module: app), aby dodać usługi Google.

F3043429cf719c47.png

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

build.gradle (moduł: aplikacja)

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

W następnym kroku włącz Pakiet SDK Map na Androida i Places API.

Konfigurowanie Google Maps Platform

Jeśli nie masz jeszcze konta Google Cloud Platform ani projektu z włączonymi płatnościami, przeczytaj przewodnik Pierwsze kroki z Google Maps Platform, by utworzyć konto rozliczeniowe i projekt.

  1. W Cloud Console kliknij menu projektu i wybierz projekt, którego chcesz użyć w tym ćwiczeniu z programowania.

  1. Włącz interfejsy API i pakiety SDK Google Maps Platform wymagane w ramach tego ćwiczenia z ćwiczeń w Google Cloud Marketplace. W tym celu wykonaj czynności opisane w tym filmie lub w tej dokumentacji.
  2. Wygeneruj klucz interfejsu API na stronie Dane logowania w Cloud Console. Odpowiednie instrukcje znajdziesz w tym filmie lub w tej dokumentacji. Wszystkie żądania wysyłane do Google Maps Platform wymagają klucza interfejsu API.

Skopiuj utworzony przed chwilą klucz interfejsu API. Wróć do Androida Studio i znajdź plik google_maps_api.xml w sekcji Android > app > res > value.

Zastąp YOUR_KEY_HERE skopiowanym kluczem interfejsu API.

Aa576e551a7a1009.png

Twoja aplikacja jest teraz skonfigurowana.

7. Edytuj plik układu

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

4e0d986480c57efa.png

  1. Po prawej stronie ekranu zobaczysz podstawowy interfejs, a u dołu znajdują się karty umożliwiające wybór projektu lub edytora tekstu. Wybierz Tekst i zastąp całą zawartość pliku układu tym:

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>

Pozwala to uzyskać interfejs podobny do tego:

1Bf786808a4697ce.png

8. Konfigurowanie paska aplikacji

Aby umożliwić użytkownikowi kliknięcie wybranego miejsca, dodaj pasek aplikacji z ikoną znajdującą bieżącą lokalizację użytkownika i wyświetlającą prawdopodobnie miejsca w pobliżu. Będzie on wyglądał :

3a17c92b613a26c5.png

Na telefonie widać tylko ikonę. Na tablecie z większą ilością miejsca także tekst.

Tworzenie ikony

  1. W eksploratorze projektu kliknij Android > app, a potem kliknij prawym przyciskiem myszy folder res i wybierz Nowy > Zasób graficzny.

Otworzy się Studio zasobów.

  1. W menu Typ ikony kliknij Ikony na pasku działań i kartach.
  2. Nazwij zasób ic_geolocate.
  3. Jako typ zasobu wybierz Klip.**
  4. Kliknij grafikę obok Clip art.

Otworzy się okno Wybierz ikonę.

  1. Wybierz ikonę.

Aby znaleźć powiązane z nimi ikony, użyj paska wyszukiwania.

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

Ikona moja lokalizacja jest taka sama jak ta w aplikacji Mapy Google, gdy użytkownik chce zrobić zdjęcie aparatu w bieżącej lokalizacji.

  1. Kliknij OK > Dalej > Zakończ, a następnie potwierdź, że istnieje nowy folder o nazwie drawable, który zawiera nowe pliki ikon.

b9e0196137ed18ae.png

Dodawanie zasobów ciągu znaków

  1. W eksploratorze projektu kliknij Android > app > res > values, a następnie otwórz plik strings.xml.
  2. Dodaj te wiersze po <string name="title_activity_maps">Map</string>:

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żą do dodawania znaczników 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 potem kliknij prawym przyciskiem myszy folder res i wybierz Nowy > Katalog, aby utworzyć nowy podkatalog w sekcji app/src/main/res.
  2. Nazwij katalog menu.
  3. Kliknij prawym przyciskiem myszy folder menu i wybierz Nowy > Plik.
  4. Nazwij plik 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ń sekcję Android & gt; app > res > values, a następnie otwórz plik styles.xml.
  2. W tagu <style> zmień właściwość nadrzędną na "Theme.AppCompat.NoActionBar".
  3. Zwróć uwagę na właściwość name, której użyjesz w następnym kroku.

styles.xml

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

Zaktualizuj motyw aplikacji w pliku AndroidManifest.xml

  1. Kliknij Android > app > manifests, i otwórz plik AndroidManifest.xml.
  2. Znajdź wiersz android:theme i zmień lub potwierdź wartość, która ma być @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 teraz zacząć programować.

9. Inicjowanie aplikacji

  1. Znajdź plik MapsActivity.java w eksploratorze projektu.

Jest on w folderze odpowiadającym pakietowi utworzonemu w kroku 1 dla aplikacji.

8b0fa27d417f5f55.png

  1. Otwórz plik w edytorze kodu Java.

Importowanie pakietu SDK Miejsc i innych zależności

Dodaj te wiersze u góry tabeli MapsActivity.java, zastępując istniejące instrukcje importu.

Obejmują one istniejące importy i umożliwiają dodanie wielu innych elementów używanych w kodzie w tym ćwiczeniu z programowania.

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 Android X, aby zapewnić zgodność wsteczną, więc musisz go zdefiniować, aby poszerzyć pole AppCompatActivity. Zastępuje rozszerzenie FragmentActivity, które jest domyślnie zdefiniowane w przypadku aktywności na mapie.

public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {

Dodawanie zmiennych klasy

Następnie zadeklaruj różne zmienne klas używane w różnych metodach klasy. Obejmują one elementy interfejsu i kody stanu. Powinny one znajdować się poniżej deklaracji 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ć uprawnienia użytkowników w środowisku wykonawczym dotyczące usług lokalizacyjnych, skonfigurować elementy interfejsu i utworzyć klienta interfejsu Places API.

Dodaj następujące wiersze kodu dotyczące paska narzędzi działań, konfiguracji widoków danych i klienta Miejsc na końcu obecnej 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 na pasku aplikacji (z 1 elementem, ikoną Wybierz miejsce) i kliknij ikonę 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);

        }
    }

Testowanie

  1. W Android Studio kliknij Uruchom lub Uruchom menu > Uruchom „app'”.

28bea91c68c36fb2.png

  1. Musisz wybrać cel wdrożenia. Na tej liście powinien być widoczny emulator uruchomiony. Wybierz ją, a Android Studio wdroży aplikację w emulatorze.

F44658CA91f6f41a.png

Po kilku chwilach aplikacja się uruchamia. Wyświetlasz mapę w Sydney w Australii z jednym przyciskiem i listą niezapełnionych miejsc.

68eb8c70f4748350.png

Mapa nie zostanie przeniesiona do lokalizacji użytkownika, chyba że poprosisz o dostęp do lokalizacji urządzenia.

10. Prośba o dostęp do lokalizacji i jej obsługa

Poproś o dostęp do lokalizacji, gdy mapa będzie gotowa

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

Wklej ten kod pod nowo utworzoną 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 obecnej metody onMapReady, aby włączyć sterowanie powiększeniem i poprosić użytkownika o dostęp 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 z żądanych uprawnień

Gdy użytkownik odpowie na okno z prośbą o zgodę na wykorzystanie danych, wywołanie zwrotne jest wywoływane przez Androida.

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. Pobierz bieżącą lokalizację i pobierz prawdopodobne miejsca

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

Wywołanie interfejsu API FindCurrentPlace i obsługuj odpowiedź

getCurrentPlaceLikelihoods tworzy findCurrentPlaceRequest i wywołuje zadanie Places API findCurrentPlace. Jeśli zadanie zostanie ukończone, zostanie zwrócony obiekt findCurrentPlaceResponse zawierający listę obiektów placeLikelihood. Każda z nich ma kilka właściwości, w tym nazwę i adres miejsca oraz prawdopodobieństwo, że znajdziesz się w tym miejscu (wartość podwójna od 0 do 1). Ta metoda obsługuje odpowiedzi, tworząc listy miejsc z placeLikelihoods.

Kod ten analizuje 5 najpopularniejszych miejsc i dodaje do tej listy te, które mają prawdopodobieństwo wyższe niż 0. Jeśli chcesz wyświetlić wartość większą lub mniejszą niż 5, zmodyfikuj stałą M_MAX_ENTRIES.

Wklej ten kod po metodzie onMapReady.

MapsActivity.java getCurrentPlaceLikeliationals()

   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());
                            }
                        }
                    }
                });
    }

Umieść kamerę na mapie w bieżącej lokalizacji urządzenia

Jeśli użytkownik pozwoli na korzystanie z tej funkcji, aplikacja pobierze jego najnowszą lokalizację, a następnie powiększy kamerę.

Jeśli użytkownik odmówi przyznania uprawnień, aplikacja przeniesie aparat do domyślnej lokalizacji zdefiniowanej wśród stałych 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 dostępu do lokalizacji, gdy użytkownik kliknie Wybierz miejsce

Gdy użytkownik kliknie Wybierz miejsce, ta metoda sprawdzi dostęp do lokalizacji i wyświetli użytkownikowi prośbę o przyznanie uprawnień, jeśli jej nie przyzna.

Jeśli użytkownik udzielił zgody, ta metoda wywołuje metodę getDeviceLocation, by rozpocząć proces pobierania informacji o aktualnie dostępnych miejscach.

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

MapsActivity.java selectCurrentPlace()

   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. Po zdefiniowaniu elementu pickCurrentPlace znajdź wiersz w onOptionsItemSelected(), który wywołuje polecenie pickCurrentPlace, i usuń komentarz.

MapsActivity.java onOptionItemSelected()

           case R.id.action_geolocate:

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

Testowanie

Jeśli uruchomisz aplikację teraz i klikniesz Wybierz miejsce, aplikacja powinna poprosić o dostęp do lokalizacji.

  • Jeśli zezwolisz na dostęp, preferencje zostaną zapisane i nie pojawi się pytanie. Gdy odmówisz zgody, po następnym kliknięciu przycisku pojawi się prośba.
  • getPlaceLikelihoods pobrał(a) prawdopodobne bieżące miejsca, ale ListView ich nie wyświetla. W Android Studio możesz kliknąć ⌘6, aby sprawdzić dzienniki w Logcat pod kątem instrukcji oznaczonych tagiem MapsActivity, aby sprawdzić, czy nowe metody działają prawidłowo.
  • Jeśli przyznasz odpowiednie uprawnienia, dzienniki będą zawierać instrukcję Latitude: oraz instrukcję Longitude: wykrywającą lokalizację urządzenia. Jeśli do określenia lokalizacji dla emulatora wcześniej użyto Map Google i rozwiniętego menu emulatora, instrukcje te wskazują tę lokalizację.
  • Jeśli Udało się wywołać interfejs findCurrentPlace, dzienniki zawierają 5 informacji, które wydrukują imiona i nazwiska oraz lokalizacje pięciu miejsc.

D9896a245b81bf3.png

12. Wypełnij selektor bieżącego miejsca

Konfigurowanie modułu obsługi wybranych miejsc

Zastanówmy się, co mamy zrobić, gdy użytkownik kliknie pozycję w ListView. Aby potwierdzić wybór użytkownika, który jest w danym miejscu, możesz dodać znacznik do mapy w tym miejscu. Jeśli użytkownik kliknie ten znacznik, wyświetli się okno informacyjne z nazwą i adresem miejsca.

Wklej ten moduł do 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 listy

Mając już listę z największym prawdopodobieństwem odwiedzanej przez użytkownika miejsca, możesz wyświetlić te opcje w ListView. Możesz też ustawić detektor kliknięć ListView tak, aby używał właśnie zdefiniowanego modułu obsługi kliknięć.

Wklej tę metodę po module 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 fillPlacesList jest zdefiniowany, znajdź wiersz na końcu findPlaceLikelihoods, który wywołuje fillPlacesList, i cofnij jego komentarz.

MapsActivity.java FillPlaceLikeliationals()

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

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

13. Uruchom aplikację

Testowanie miejsca

  1. Ponownie uruchom aplikację.

Tym razem gdy klikniesz Wybierz miejsce, aplikacja zapełni listę na podstawie nazw miejsc w pobliżu tej lokalizacji. Niedaleko tej lokalizacji na Maui znajdują się takie miejsca jak Ululani&hl=pl's Hawaiian Shave Ice i Sugar Beach Bake Shop. Kilka miejsc znajduje się bardzo blisko współrzędnych lokalizacji, dlatego jest to lista prawdopodobnie odwiedzonych przez Ciebie miejsc.

  1. Kliknij nazwę miejsca w kolumnie ListView.

Powinien pojawić się znacznik na mapie.

  1. Kliknij znacznik.

Wyświetlą się szczegółowe informacje o miejscu.

e52303cc0de6a513.png 864c74342fb52a01.png

Testowanie innej lokalizacji

Jeśli chcesz zmienić lokalizację i korzystasz z emulatora, lokalizacja urządzenia nie jest automatycznie aktualizowana podczas aktualizowania współrzędnych lokalizacji w emulatorze i rozszerzonym menu.

Aby obejść ten problem, wykonaj te czynności, aby wymusić aktualizację lokalizacji emulatora:

  1. Otwórz Mapy Google.
  2. Wybierz ... > 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 podać lokalizację 49, 2768 i Długość geograficzna: -123, 1142 w celu ustawienia lokalizacji na centrum Vancouver w Kanadzie.
  4. Sprawdź, czy w Mapach Google zostały niedawno wprowadzone nowe współrzędne. Może być konieczne kliknięcie przycisku Moja lokalizacja w aplikacji Mapy Google.
  5. Wróć do aplikacji Aktualne miejsce i kliknij Wybierz miejsce, aby zobaczyć mapę na nowych współrzędnych i zobaczyć nową listę prawdopodobnie aktualnych miejsc.

9adb99d1ce25c184.png

Gotowe! Udało Ci się utworzyć prostą aplikację, która sprawdza miejsca w bieżącej lokalizacji i przewiduje, które z nich są aktualne. Miłego korzystania z punktów.

Teraz możesz uruchomić aplikację z wprowadzonymi przez Ciebie zmianami, aby zakończyć ten dodatkowy krok!

14. Dalsze kroki

Aby zapobiec kradzieży klucza interfejsu API, musisz go zabezpieczyć tak, by mógł z niego korzystać tylko Twoja aplikacja na Androida. Jeśli pozostawisz to pole nieograniczone, każda osoba, która będzie miała Twój klucz, będzie mogła go używać do wywoływania interfejsów API Google Maps Platform i do naliczania opłat.

Pobieranie certyfikatu SHA-1

Będzie Ci ona potrzebna później, gdy ograniczysz klucze interfejsu API. Poniżej znajdziesz instrukcje, jak uzyskać certyfikat debugowania.

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

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

W systemach Windows Vista i Windows 7 uruchom następujące polecenie:

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

Dane wyjściowe powinny wyglądać podobnie 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 certyfikatu SHA-1 certyfikatu. Odcisk cyfrowy jest sekwencją 20 cyfr szesnastkowych rozdzielonych dwukropkami.

Gdy wszystko będzie gotowe do opublikowania aplikacji, wykonaj instrukcje opisane w tej dokumentacji, aby pobrać certyfikat wersji.

Dodawanie ograniczeń do klucza interfejsu API

  1. W Cloud Console otwórz APIs & Services > Credentials (Dane logowania).

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

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

316b052c621ee91c.png

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

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ć sobie dodatkową ochronę, ustaw Ograniczenia interfejsu API, wykonując opisane poniżej czynności.
  2. Po wprowadzeniu ograniczeń interfejsu API wybierz Ogranicz klucz.
  3. Wybierz pakiet SDK Maps na Androida i interfejs Places API.
  4. Kliknij Gotowe i Zapisz.

15. Gratulacje

Udało Ci się utworzyć prostą aplikację, która sprawdza, które miejsca w danej lokalizacji są najbardziej prawdopodobne, i dodać do mapy znacznik miejsca wybranego przez użytkownika.

Więcej informacji