1. Прежде чем начать
Узнайте, как использовать платформу Google Карт и Places SDK для Android, чтобы предоставить пользователям список мест для определения их текущего местоположения.
Предпосылки
- Базовые навыки Java
Что ты будешь делать?
- Добавьте карту в приложение для Android.
- Используйте разрешения на определение местоположения для геолокации пользователя.
- Поиск мест рядом с текущим местоположением пользователя.
- Представить пользователю вероятные места для определения его текущего местоположения.
Что вы построите
Вы создаёте своё Android-приложение с нуля, но можете скачать пример кода для сравнения при отладке. Загрузите пример кода с GitHub или, если у вас настроен Git для работы из командной строки, введите следующее:
git clone https://github.com/googlecodelabs/current-place-picker-android.git
Если во время работы над этой лабораторной работой у вас возникнут какие-либо проблемы (ошибки кода, грамматические ошибки, неясные формулировки и т. д.), сообщите о них, воспользовавшись ссылкой «Сообщить об ошибке» в левом нижнем углу лабораторной работы.
2. Начните
Перед началом выполнения этой лабораторной работы вам необходимо настроить следующее:
Android Studio
Загрузите Android Studio с сайта https://developer.android.com/studio .
Если у вас уже установлен Android Studio, убедитесь, что у вас установлена последняя версия, нажав Android Studio > Проверить обновления... .
Эта лабораторная работа была написана с использованием Android Studio 3.4.
Android SDK
В Android Studio вы можете настроить необходимые SDK с помощью SDK Manager. В этой лабораторной работе используется Android Q SDK.
- На экране приветствия Android Studio нажмите Настроить > Менеджер SDK .
- Установите флажок нужного вам SDK, затем нажмите «Применить» .
Если у вас еще нет SDK, начнется загрузка SDK на ваш компьютер.
Сервисы Google Play
Из менеджера SDK вам также необходимо установить сервисы Google Play.
- Откройте вкладку «Инструменты SDK» и установите флажок «Сервисы Google Play» .
Обновите, если статус показывает Доступно обновление .
3. Подготовьте эмулятор.
Чтобы запустить приложение, вы можете подключить свое устройство или использовать эмулятор Android.
Если вы используете собственное устройство, перейдите к разделу «Инструкции для реального устройства: обновление сервисов Google Play» в конце этой страницы.
Добавить эмулятор
- На экране приветствия Android Studio нажмите Настроить > AVD Manager .
Откроется диалоговое окно диспетчера виртуальных устройств Android .
- Нажмите «Создать виртуальное устройство...» , чтобы открыть список устройств, которые вы можете выбрать.
- Выберите устройство с Play
значок в столбце Play Маркет и нажмите Далее .
Вы увидите набор образов системы, которые можно установить. Если рядом с версией Q для Android 9.+ (Google Play) есть кнопка «Загрузить» , нажмите «Загрузить» .
- Нажмите «Далее» , чтобы дать имя вашему виртуальному устройству, затем нажмите « Готово» .
Вы возвращаетесь к списку Ваших виртуальных устройств .
- Нажмите «Пуск».
рядом с вашим новым устройством:
Через несколько мгновений эмулятор откроется.
Инструкции для эмулятора — обновление сервисов Google Play
- После запуска эмулятора нажмите ... на появившейся панели навигации**.**
Откроется диалоговое окно «Расширенные элементы управления» .
- Нажмите Google Play в меню.
Если доступно обновление, нажмите Обновить .
- Войдите в эмулятор, используя учетную запись Google.
Вы можете использовать свою собственную учетную запись или бесплатно создать новую, чтобы отделить результаты тестирования от ваших персональных данных.
Затем Google Play открывает сервисы Google Play.
- Нажмите «Обновить» , чтобы получить последнюю версию сервисов Google Play.
Если вам будет предложено завершить настройку учетной записи и добавить способ оплаты, нажмите «Пропустить» .
Установить местоположение в эмуляторе
- После запуска эмулятора введите «карты» в строку поиска на главном экране, чтобы открыть значок приложения Google Maps.
- Нажмите на значок для запуска.
Вы видите карту по умолчанию.
- В правом нижнем углу карты нажмите «Ваше местоположение» .
.
Вас попросят предоставить телефону разрешение на использование данных о местоположении.
- Нажмите ... , чтобы открыть меню расширенных элементов управления .
- Откройте вкладку Местоположение .
- Введите широту и долготу.
Введите сюда все, что вам нравится, но убедитесь, что это место находится в районе, где много других мест.
(Используйте широту 20,7818 и долготу -156,4624 для города Кихеи на острове Мауи, Гавайи, чтобы воспроизвести результаты этой лабораторной работы.)
- Нажмите «Отправить» , и карта обновится с указанием этого местоположения.
Теперь вы готовы запустить свое приложение и протестировать его с учетом местоположения.
Инструкции для реального устройства — обновление сервисов Google Play
Если вы используете настоящее Android-устройство, то сделайте следующее:
- Используйте строку поиска на главном экране для поиска и открытия сервисов Google Play.
- Нажмите «Подробнее» .
Если доступно, нажмите Обновить .
4. Создайте оболочку приложения с активностью Google Maps.
- На экране приветствия Android Studio выберите Начать новый проект Android Studio .
- На вкладке «Телефон и планшет» выберите «Действия в Google Картах» .
Откроется диалоговое окно « Настройка проекта» . Здесь вы можете указать имя своего приложения и создать пакет на основе своего домена.
Ниже приведены настройки приложения Current Place, которое соответствует пакету com.google.codelab.currentplace
.
- Выберите Java в качестве языка и выберите Использовать androidx. artifacts *.
Для остальных настроек оставьте значения по умолчанию.
- Нажмите кнопку Готово .
5. Добавьте зависимости Google Services в файл сборки Gradle.
Для доступа к данным о местоположении в Android вам потребуется API Google Location and Activity Recognition из сервисов Google Play. Подробнее о добавлении этого и других API сервисов Google Play см. в разделе «Настройка сервисов Google Play» .
Проекты Android Studio обычно содержат два файла build.gradle
. Один предназначен для всего проекта, а другой — для приложения. Если вы используете проводник проектов Android Studio в режиме Android , вы увидите оба файла в папке Gradle Scripts
. Чтобы добавить сервисы Google, необходимо отредактировать файл build.gradle (Module: app)
.
- Добавьте две строки в раздел
dependencies
, чтобы добавить службы Google для определения местоположения и API Places ( пример кода в контексте ).
build.gradle (Модуль: 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. Включите API платформы Google Карт и получите ключ API.
Для следующего шага включения вам необходимо включить Maps SDK для Android и Places API .
Настройте платформу Google Карт
Если у вас еще нет учетной записи Google Cloud Platform и проекта с включенным выставлением счетов, ознакомьтесь с руководством « Начало работы с Google Maps Platform», чтобы создать учетную запись для выставления счетов и проект.
- В Cloud Console щелкните раскрывающееся меню проектов и выберите проект, который вы хотите использовать для этой кодовой лаборатории.
- Включите API и SDK платформы Google Карт, необходимые для этой лабораторной работы, в Google Cloud Marketplace . Для этого следуйте инструкциям в этом видео или в этой документации .
- Сгенерируйте ключ API на странице «Учётные данные» в Cloud Console. Вы можете следовать инструкциям в этом видео или в этой документации . Для всех запросов к платформе Google Карт требуется ключ API.
Скопируйте только что созданный ключ API. Вернитесь в Android Studio и найдите файл google_maps_api.xml
в разделе Android > app > res > value s.
Замените YOUR_KEY_HERE
на скопированный вами ключ API.
Теперь ваше приложение настроено.
7. Отредактируйте файл макета.
- В обозревателе проектов откройте файл
activity_maps.xml
в папке Android >app
>res
>layout
.
- В правой части экрана откроется базовый интерфейс с вкладками внизу, позволяющими выбрать редактор «Дизайн» или «Текст» для вашего макета. Выберите «Текст» и замените всё содержимое файла макета следующим:
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>
Это даст вам пользовательский интерфейс, который будет выглядеть следующим образом:
8. Настройте панель приложений.
Чтобы дать пользователю кнопку, по которой он может выбрать своё текущее место, добавьте панель приложения со значком, которая находит текущее место пользователя и отображает близлежащие вероятные места. Это будет выглядеть так:
На телефоне отображается только значок. На планшете с большим пространством отображается и текст.
Создать значок
- В обозревателе проектов нажмите Android > app , затем щелкните правой кнопкой мыши папку res и выберите New > Image Asset .
Открывается Студия Активов .
- В меню «Тип значка» выберите «Значки панели действий и вкладок» .
- Назовите свой актив
ic_geolocate
. - Выберите Клип-арт в качестве типа актива**.**
- Щелкните по изображению рядом с клипартом .
Откроется окно «Выбрать значок» .
- Выберите значок.
Вы можете использовать строку поиска, чтобы найти значки, соответствующие вашим намерениям.
- Найдите
location
и выберите значок, соответствующий местоположению.
Значок «Мое местоположение» такой же, как тот, который используется в приложении Google Maps, когда пользователь хочет прикрепить камеру к своему текущему местоположению.
- Нажмите «ОК» > «Далее» > «Готово» и убедитесь, что создана новая папка с именем
drawable
, содержащая новые файлы значков.
Добавить строковые ресурсы
- В обозревателе проектов выберите Android > app > res > values и откройте файл
strings.xml
. - Добавьте следующие строки после
<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>
Первая строка используется на панели приложения, когда рядом со значком есть место для текстовой подписи. Остальные строки используются для маркеров, добавляемых на карту.
Теперь код в файле выглядит так:
<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>
Добавить панель приложений
- В обозревателе проектов нажмите Android > app , затем щелкните правой кнопкой мыши папку
res
и выберите New > Directory , чтобы создать новый подкаталог вapp/src/main/res
. - Назовите
menu
каталога. - Щелкните правой кнопкой мыши папку
menu
и выберите Создать > Файл . - Назовите файл
menu.xml
. - Вставьте этот код:
меню.xml
<?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>
Обновите стиль панели приложений
- В обозревателе проектов разверните Android >
app
>res
>values
и откройте файлstyles.xml
внутри. - В теге
<style>
измените родительское свойство на"Theme.AppCompat.NoActionBar"
. - Запишите свойство
name
, которое вы будете использовать на следующем шаге.
стили.xml
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
Обновите тему приложения в AndroidManifest.xml
- Нажмите Android >
app
>manifests
и откройте файлAndroidManifest.xml
. - Найдите строку
android:theme
и измените или подтвердите значение на@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">
Теперь вы готовы приступить к программированию!
9. Инициализируйте приложение.
- В обозревателе проектов найдите файл
MapsActivity.java
.
Он находится в папке, соответствующей пакету, который вы создали для своего приложения на шаге 1.
- Откройте файл, и вы окажетесь в редакторе кода Java.
Импортируйте Places SDK и другие зависимости
Добавьте эти строки в начало MapsActivity.java
, заменив существующие операторы импорта.
Они включают в себя существующие импорты и добавляют множество новых, используемых в коде в этой лабораторной работе.
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;
Обновить сигнатуру класса
API Places использует компоненты AndroidX для поддержки обратной совместимости, поэтому необходимо определить его как расширение AppCompatActivity
. Оно заменяет расширение FragmentActivity
, которое определено по умолчанию для действия «Карты».
public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {
Добавить переменные класса
Затем объявите различные переменные класса, используемые в разных методах класса. Они включают элементы пользовательского интерфейса и коды состояния. Они должны располагаться сразу под объявлением переменной для 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;
Обновите метод onCreate
Вам потребуется обновить метод onCreate
для обработки разрешений пользователя во время выполнения для служб определения местоположения, настройки элементов пользовательского интерфейса и создания клиента API Places.
Добавьте следующие строки кода, касающиеся панели инструментов действий, настройки представлений и клиента Places, в конец существующего метода 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);
}
Добавьте код для меню панели вашего приложения
Эти два метода добавляют меню панели приложения (с одним элементом — значком Pick Place) и обрабатывают нажатие пользователем на значок.
Скопируйте эти два метода в свой файл после метода onCreate
.
MapsActivity.java onCreateOptionsMenu() и 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);
}
}
Проверьте это
- В Android Studio выберите пункт Выполнить или меню Выполнить > Запустить 'приложение' .
- Вам будет предложено выбрать цель развертывания. Запущенный эмулятор должен появиться в этом списке. Выберите его, и Android Studio развернет приложение в эмуляторе.
Через несколько мгновений приложение запустится. Вы увидите карту с центром в Сиднее, Австралия, с единственной кнопкой и списком незаселённых мест.
Фокус карты не переместится на местоположение пользователя, пока вы не запросите разрешение на доступ к местоположению устройства.
10. Запрос и обработка разрешений на местоположение
Запросите разрешение на определение местоположения после того, как карта будет готова
- Определите метод
getLocationPermission
, который запрашивает разрешения пользователя.
Вставьте этот код под методом 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);
}
}
- Добавьте две строки в конец существующего метода
onMapReady
, чтобы включить управление масштабированием и запросить у пользователя разрешения на определение местоположения.
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();
}
Обрабатывать результаты запрошенных разрешений
Когда пользователь отвечает на диалоговое окно запроса разрешения, Android вызывает этот обратный вызов.
Вставьте этот код после метода 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. Получите текущее местоположение и найдите вероятные места.
Когда пользователь нажимает кнопку «Выбрать место» на панели приложения, приложение вызывает метод pickCurrentPlace()
, который, в свою очередь, вызывает метод getDeviceLocation()
который вы определили ранее. Метод getDeviceLocation
вызывает другой метод, getCurrentPlaceLikelihoods,
после получения последнего местоположения устройства.
Вызовите API findCurrentPlace и обработайте ответ.
getCurrentPlaceLikelihoods
создаёт запрос findCurrentPlaceRequest
и вызывает задачу findCurrentPlace
API Places. В случае успешного выполнения задачи возвращается ответ findCurrentPlaceResponse
, содержащий список объектов placeLikelihood
. Каждый из них имеет ряд свойств, включая название и адрес места, а также вероятность того, что вы находитесь в этом месте (значение типа double от 0 до 1). Этот метод обрабатывает ответ, формируя списки информации о месте из placeLikelihoods
.
Этот код перебирает пять наиболее вероятных мест и добавляет те, вероятность которых больше 0, в список, который затем отображается. Если вы хотите отобразить больше или меньше пяти мест, отредактируйте константу M_MAX_ENTRIES
.
Вставьте этот код после метода 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());
}
}
}
});
}
Переместите камеру карты в текущее местоположение устройства.
Если пользователь дает разрешение, приложение получает данные о последнем местоположении пользователя и перемещает камеру в центр этого местоположения.
Если пользователь отказывает в разрешении, приложение просто перемещает камеру в местоположение по умолчанию, определенное среди констант в начале этой страницы (в примере кода это Сидней, Австралия).
Вставьте этот код после метода 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());
}
}
Проверяйте разрешения на определение местоположения, когда пользователь нажимает «Выбрать место»
Когда пользователь нажимает «Выбрать место» , этот метод проверяет разрешения на определение местоположения и запрашивает у пользователя разрешение, если оно не было предоставлено.
Если пользователь дал разрешение, то метод вызывает getDeviceLocation
, чтобы инициировать процесс получения текущих вероятных мест.
- Добавьте этот метод после
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();
}
}
- Теперь, когда
pickCurrentPlace
определен, найдите строку вonOptionsItemSelected()
, которая вызываетpickCurrentPlace
, и раскомментируйте ее.
MapsActivity.java onOptionItemSelected()
case R.id.action_geolocate:
// COMMENTED OUT UNTIL WE DEFINE THE METHOD
// Present the Current Place picker
pickCurrentPlace();
return true;
Проверьте это
Если вы сейчас запустите приложение и нажмете «Выбрать место» , оно должно запросить разрешение на определение местоположения.
- Если вы дадите разрешение, эта настройка сохранится, и запрос не будет отображаться. Если вы откажетесь, запрос появится при следующем нажатии кнопки.
- Хотя
getPlaceLikelihoods
уже получил данные о вероятных текущих местах,ListView
пока их не отображает. В Android Studio вы можете нажать ⌘6 , чтобы проверить журналы Logcat на наличие операторов с тегом MapsActivity и убедиться, что новые методы работают правильно. - Если вы предоставили разрешение, в журналах будут отображаться значения
Latitude:
и «Longitude:
, показывающие обнаруженное местоположение устройства. Если ранее вы использовали Google Карты и расширенное меню эмулятора для указания местоположения эмулятора, эти значения будут содержать это местоположение. - Если вызов
findCurrentPlace
был успешным, журналы включают пять операторов, печатающих названия и местоположения пяти наиболее вероятных мест.
12. Заполните поле выбора текущего места.
Настройте обработчик для выбранных мест
Давайте подумаем о том, что должно происходить, когда пользователь щёлкает по элементу в ListView
. Чтобы подтвердить выбор текущего места, можно добавить на карту маркер в этом месте. Если пользователь щёлкнет по этому маркеру, появится информационное окно с названием и адресом места.
Вставьте этот обработчик щелчков после метода 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));
}
};
Заполнить ListView
Теперь, когда у вас есть список наиболее вероятных мест, которые пользователь в данный момент посещает, вы можете представить эти варианты пользователю в ListView
. Вы также можете настроить прослушиватель щелчков ListView
на использование обработчика щелчков, который вы только что определили.
Вставьте этот метод после обработчика щелчков:
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);
}
Теперь, когда fillPlacesList
определен, найдите строку в конце findPlaceLikelihoods
, которая вызывает fillPlacesList
, и раскомментируйте ее.
MapsActivity.java fillPlaceLikelihoods()
// COMMENTED OUT UNTIL WE DEFINE THE METHOD
// Populate the ListView
fillPlacesList();
Это весь код, необходимый для выбора текущего места!
13. Запустите приложение.
Тестовый выбор места
- Запустите приложение еще раз.
На этот раз, когда вы нажмете «Выбрать место» , приложение заполнит список названных мест поблизости. Неподалеку от этого места на Мауи находятся такие заведения, как Ululani's Hawaiian Shave Ice и Sugar Beach Bake Shop. Поскольку несколько заведений находятся очень близко к координатам местоположения, это список вероятных мест, где вы можете находиться.
- Щелкните по названию места в
ListView
.
Вы должны увидеть маркер, добавленный на карту.
- Нажмите на маркер.
Вы можете увидеть подробную информацию о месте.
Проверьте другое место
Если вы хотите изменить свое местоположение и используете эмулятор, местоположение устройства не обновляется автоматически при обновлении координат местоположения в расширенном меню эмулятора.
Чтобы обойти эту проблему, выполните следующие действия, чтобы использовать собственное приложение Google Maps для принудительного обновления местоположения эмулятора:
- Откройте Google Карты.
- Нажмите ... > Местоположение , чтобы изменить широту и долготу на новые координаты, затем нажмите Отправить .
- Например, вы можете использовать широту: 49.2768 и долготу: -123.1142, чтобы указать местоположение в центре Ванкувера, Канада.
- Убедитесь, что Google Карты центрировались по вашим новым координатам. Возможно, вам потребуется нажать кнопку «Моё местоположение» в приложении Google Карты, чтобы запросить центрирование.
- Вернитесь в приложение «Текущее место» и нажмите «Выбрать место», чтобы отобразить карту с новыми координатами и увидеть новый список вероятных текущих мест.
Вот и всё! Вы создали простое приложение, которое проверяет места в вашем текущем местоположении и даёт вам оценку вероятности того, где вы находитесь. Наслаждайтесь!
А теперь запустите приложение с внесенными вами изменениями, чтобы завершить этот бонусный шаг!
14. Дальнейшие шаги
Чтобы предотвратить кражу вашего API-ключа, необходимо защитить его так, чтобы его могло использовать только ваше Android-приложение. Если оставить его без присмотра, любой, кто владеет вашим ключом, может использовать его для вызова API платформы Google Карт и списать с вас средства.
Получите сертификат SHA-1
Это понадобится вам позже, когда вы ограничите доступ к своим API-ключам. Ниже приведены инструкции по получению отладочного сертификата.
Для Linux или macOS откройте окно терминала и введите следующее:
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
Для Windows Vista и Windows 7 выполните следующую команду:
keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android
Вы должны увидеть примерно такой вывод:
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
Строка, начинающаяся с SHA1, содержит отпечаток сертификата SHA-1. Отпечаток представляет собой последовательность из 20 двузначных шестнадцатеричных чисел, разделённых двоеточиями.
Когда вы будете готовы выпустить приложение, воспользуйтесь инструкциями в этой документации , чтобы получить сертификат выпуска.
Добавьте ограничения к вашему ключу API
- В Cloud Console перейдите в раздел API и службы > Учетные данные .
Ключ, который вы использовали для этого приложения, должен быть указан в разделе «Ключи API».
- Щелкните
для редактирования основных настроек.
- На странице ключа API, после ограничений ключа , задайте ограничения приложения , выполнив следующие действия:
- Выберите приложения Android и следуйте инструкциям.
- Нажмите Добавить элемент .
- Введите имя вашего пакета и отпечаток сертификата SHA-1 (полученный в предыдущем разделе).
Например:
com.google.codelab.currentplace
BB:0D:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:75s
- Для дополнительной защиты установите ограничения API , выполнив следующие действия.
- После ограничений API выберите Ограничить ключ .
- Выберите Maps SDK для Android и Places API.
- Нажмите «Готово» и «Сохранить».
15. Поздравления
Вы создали простое приложение, которое проверяет наиболее вероятные места в текущем местоположении и добавляет на карту маркер для места, выбранного пользователем.
Узнать больше
- Для ускорения разработки используйте библиотеку утилит Maps SDK for Android . Эти утилиты выполняют основную работу для некоторых из самых популярных задач в приложениях, использующих платформу Google Карт.
- Дополнительные примеры кода, демонстрирующие большинство функций пакетов SDK платформы Google Карт для Android, можно найти в репозиториях клонов образцов Maps SDK для Android и демонстрационных версий Places SDK для Android .
- Чтобы узнать, как обрабатывать разрешения на определение местоположения в трех состояниях в Android Q, выполните практическую работу « Получение обновлений местоположения в Android с помощью Kotlin ».