В этом руководстве объясняются изменения между библиотекой совместимости Places и новой автономной версией Places SDK для Android . Если вы использовали библиотеку совместимости Places вместо перехода на новую автономную версию Places SDK для Android, в этом руководстве показано, как обновить ваши проекты для использования новой версии Places SDK для Android.
Единственным способом получить доступ к функциям и исправлениям ошибок в Places SDK для Android выше версии 2.6.0 будет использование Places SDK для Android. Google рекомендует обновить библиотеку совместимости до новой версии Places SDK для Android как можно скорее.
Ошибка: 9005 PLACES_API_RATE_LIMIT_EXCEEDED
Что изменилось?
Основные направления изменений следующие:
- Новая версия Places SDK для Android распространяется как статическая клиентская библиотека. До января 2019 года Places SDK для Android был доступен через сервисы Google Play. С тех пор была предоставлена библиотека совместимости Places для облегчения перехода на новый Places SDK для Android.
- Существуют совершенно новые методы .
- Маски полей теперь поддерживаются для методов, которые возвращают данные о месте. Вы можете использовать маски полей, чтобы указать, какие типы данных о месте возвращать.
- Улучшены коды состояния, используемые для сообщения об ошибках.
- Автозаполнение теперь поддерживает токены сеанса .
- Выбор места больше недоступен .
О библиотеке совместимости Places
В январе 2019 года с выпуском версии 1.0 автономного Places SDK для Android компания Google предоставила библиотеку совместимости, которая поможет осуществить миграцию с выведенной из эксплуатации версии Google Play Services Places SDK для Android ( com.google.android.gms:play-services-places
).
Эта библиотека совместимости была временно предоставлена для перенаправления и перевода вызовов API, направленных на версию Google Play Services, в новую автономную версию, пока разработчики не смогут перенести свой код для использования новых имен в автономном SDK. Для каждой версии Places SDK для Android, выпущенной с версии 1.0 по версию 2.6.0, была выпущена соответствующая версия библиотеки совместимости Places для предоставления эквивалентной функциональности.
Заморозка и прекращение поддержки библиотеки совместимости Places
Все версии библиотеки совместимости для Places SDK для Android устарели с 31 марта 2022 года. Версия 2.6.0 — последняя версия библиотеки совместимости Places. Единственным способом получить доступ к функциям и исправлениям ошибок в Places SDK для Android выше версии 2.6.0 будет использование Places SDK для Android.
Google рекомендует вам перейти на Places SDK для Android, чтобы получить доступ к новым функциям и исправлениям критических ошибок для выпусков выше версии 2.6.0. Если вы в настоящее время используете библиотеку совместимости, выполните шаги ниже в разделе Установка Places SDK для Android, чтобы перейти на Places SDK для Android.
Установить клиентскую библиотеку
Новая версия Places SDK для Android распространяется как статическая клиентская библиотека.
Используйте Maven для добавления Places SDK для Android в ваш проект Android Studio:
Если вы в настоящее время используете библиотеку совместимости Places :
Замените следующую строку в разделе
dependencies
:implementation 'com.google.android.libraries.places:places-compat:X.Y.Z'
С помощью этой строки можно переключиться на Places SDK для Android:
implementation("com.google.android.libraries.places:places:4.1.0")
Если вы в настоящее время используете версию Places SDK для Android от Play Services :
Замените следующую строку в разделе
dependencies
:implementation 'com.google.android.gms:play-services-places:X.Y.Z'
С помощью этой строки можно переключиться на Places SDK для Android:
implementation("com.google.android.libraries.places:places:4.1.0")
Синхронизируйте свой проект Gradle.
Установите
minSdkVersion
для вашего проекта приложения на значение 23 или выше.Обновите свои ресурсы «Powered by Google»:
@drawable/powered_by_google_light // OLD @drawable/places_powered_by_google_light // NEW @drawable/powered_by_google_dark // OLD @drawable/places_powered_by_google_dark // NEW
Создайте свое приложение. Если вы видите какие-либо ошибки сборки из-за перехода на Places SDK для Android, см. разделы ниже для получения информации об устранении этих ошибок.
Инициализируйте новый клиент Places SDK
Инициализируйте новый клиент Places SDK, как показано в следующем примере:
// Add an import statement for the client library.
import com.google.android.libraries.places.api.Places;
...
// Initialize Places.
Places.initialize(getApplicationContext(), apiKey);
// Create a new Places client instance.
PlacesClient placesClient = Places.createClient(this);
Коды статуса
Изменился код статуса для ошибок лимита QPS. Ошибки лимита QPS теперь возвращаются через PlaceStatusCodes.OVER_QUERY_LIMIT
. Лимитов QPD больше нет.
Добавлены следующие коды статуса:
REQUEST_DENIED
— Запрос отклонен. Возможные причины этого:- API-ключ не был предоставлен.
- Предоставлен недействительный ключ API.
- API Places не включен в облачной консоли.
- API-ключ был предоставлен с неверными ограничениями ключа.
INVALID_REQUEST
— Запрос недействителен из-за отсутствующего или недопустимого аргумента.NOT_FOUND
— По данному запросу результат не найден.
Новые методы
Новая версия Places SDK для Android представляет совершенно новые методы, разработанные для обеспечения согласованности. Все новые методы соответствуют следующим:
- Конечные точки больше не используют глагол
get
. - Объекты запроса и ответа имеют то же имя, что и соответствующий клиентский метод.
- Объекты запроса теперь имеют конструкторы; требуемые параметры передаются как параметры конструктора запроса.
- Буферы больше не используются.
В этом разделе представлены новые методы и показано, как они работают.
Найти место по идентификатору
Используйте fetchPlace()
для получения подробной информации о конкретном месте. fetchPlace()
функционирует аналогично getPlaceById()
.
Чтобы найти место, выполните следующие действия:
Вызовите
fetchPlace()
, передав объектFetchPlaceRequest
указав идентификатор места и список полей , определяющих возвращаемые данные места.// Define a Place ID. String placeId = "INSERT_PLACE_ID_HERE"; // Specify the fields to return. List<Place.Field> placeFields = Arrays.asList(Place.Field.ID, Place.Field.DISPLAY_NAME); // Construct a request object, passing the place ID and fields array. FetchPlaceRequest request = FetchPlaceRequest.builder(placeId, placeFields) .build();
Вызовите
addOnSuccessListener()
для обработкиFetchPlaceResponse
. Возвращается один результатPlace
.// Add a listener to handle the response. placesClient.fetchPlace(request).addOnSuccessListener((response) -> { Place place = response.getPlace(); Log.i(TAG, "Place found: " + place.getName()); }).addOnFailureListener((exception) -> { if (exception instanceof ApiException) { ApiException apiException = (ApiException) exception; int statusCode = apiException.getStatusCode(); // Handle error with given status code. Log.e(TAG, "Place not found: " + exception.getMessage()); } });
Получить фото места
Используйте fetchPhoto()
для получения фотографии места. fetchPhoto()
возвращает фотографии для места. Шаблон запроса фотографии был упрощен. Теперь вы можете запрашивать PhotoMetadata
непосредственно из объекта Place
; отдельный запрос больше не нужен. Фотографии могут иметь максимальную ширину или высоту 1600 пикселей. fetchPhoto()
функционирует аналогично getPhoto()
.
Чтобы получить фотографии места, выполните следующие действия:
Настройте вызов
fetchPlace()
. Обязательно включите полеPHOTO_METADATAS
в ваш запрос:List<Place.Field> fields = Arrays.asList(Place.Field.PHOTO_METADATAS);
Получите объект Place (в этом примере используется
fetchPlace()
, но вы также можете использоватьfindCurrentPlace()
):FetchPlaceRequest placeRequest = FetchPlaceRequest.builder(placeId, fields).build();
Добавьте
OnSuccessListener
для получения метаданных фотографии из результирующегоPlace
вFetchPlaceResponse
, затем используйте результирующие метаданные фотографии для получения растрового изображения и текста атрибуции:placesClient.fetchPlace(placeRequest).addOnSuccessListener((response) -> { Place place = response.getPlace(); // Get the photo metadata. PhotoMetadata photoMetadata = place.getPhotoMetadatas().get(0); // Get the attribution text. String attributions = photoMetadata.getAttributions(); // Create a FetchPhotoRequest. FetchPhotoRequest photoRequest = FetchPhotoRequest.builder(photoMetadata) .setMaxWidth(500) // Optional. .setMaxHeight(300) // Optional. .build(); placesClient.fetchPhoto(photoRequest).addOnSuccessListener((fetchPhotoResponse) -> { Bitmap bitmap = fetchPhotoResponse.getBitmap(); imageView.setImageBitmap(bitmap); }).addOnFailureListener((exception) -> { if (exception instanceof ApiException) { ApiException apiException = (ApiException) exception; int statusCode = apiException.getStatusCode(); // Handle error with given status code. Log.e(TAG, "Place not found: " + exception.getMessage()); } }); });
Найти место в зависимости от местонахождения пользователя
Используйте findCurrentPlace()
для поиска текущего местоположения устройства пользователя. findCurrentPlace()
возвращает список PlaceLikelihood
, указывающих места, где устройство пользователя с наибольшей вероятностью может находиться. findCurrentPlace()
функционирует аналогично getCurrentPlace()
.
Чтобы получить текущее местоположение устройства пользователя, выполните следующие действия:
Убедитесь, что ваше приложение запрашивает разрешения
ACCESS_FINE_LOCATION
иACCESS_WIFI_STATE
. Пользователь должен предоставить разрешение на доступ к текущему местоположению своего устройства. Подробнее см. в разделе Запрос разрешений приложения .Создайте
FindCurrentPlaceRequest
, включая список типов данных о местах, которые необходимо вернуть.// Use fields to define the data types to return. List<Place.Field> placeFields = Arrays.asList(Place.Field.DISPLAY_NAME); // Use the builder to create a FindCurrentPlaceRequest. FindCurrentPlaceRequest request = FindCurrentPlaceRequest.builder(placeFields).build();
Вызовите findCurrentPlace и обработайте ответ, предварительно проверив, предоставил ли пользователь разрешение на использование местоположения своего устройства.
// Call findCurrentPlace and handle the response (first check that the user has granted permission). if (ContextCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { placesClient.findCurrentPlace(request).addOnSuccessListener(((response) -> { for (PlaceLikelihood placeLikelihood : response.getPlaceLikelihoods()) { Log.i(TAG, String.format("Place '%s' has likelihood: %f", placeLikelihood.getPlace().getName(), placeLikelihood.getLikelihood())); textView.append(String.format("Place '%s' has likelihood: %f\n", placeLikelihood.getPlace().getName(), placeLikelihood.getLikelihood())); } })).addOnFailureListener((exception) -> { if (exception instanceof ApiException) { ApiException apiException = (ApiException) exception; Log.e(TAG, "Place not found: " + apiException.getStatusCode()); } }); } else { // A local method to request required permissions; // See https://developer.android.com/training/permissions/requesting getLocationPermission(); }
Найти подсказки автозаполнения
Используйте findAutocompletePredictions()
для возврата прогнозов мест в ответ на поисковые запросы пользователя. findAutocompletePredictions()
функционирует аналогично getAutocompletePredictions()
.
В следующем примере показан вызов findAutocompletePredictions()
:
// Create a new token for the autocomplete session. Pass this to FindAutocompletePredictionsRequest,
// and once again when the user makes a selection (for example when calling fetchPlace()).
AutocompleteSessionToken token = AutocompleteSessionToken.newInstance();
// Create a RectangularBounds object.
RectangularBounds bounds = RectangularBounds.newInstance(
new LatLng(-33.880490, 151.184363),
new LatLng(-33.858754, 151.229596));
// Use the builder to create a FindAutocompletePredictionsRequest.
FindAutocompletePredictionsRequest request = FindAutocompletePredictionsRequest.builder()
// Call either setLocationBias() OR setLocationRestriction().
.setLocationBias(bounds)
//.setLocationRestriction(bounds)
.setCountry("au")
.setTypesFilter(Arrays.asList(PlaceTypes.ADDRESS))
.setSessionToken(token)
.setQuery(query)
.build();
placesClient.findAutocompletePredictions(request).addOnSuccessListener((response) -> {
for (AutocompletePrediction prediction : response.getAutocompletePredictions()) {
Log.i(TAG, prediction.getPlaceId());
Log.i(TAG, prediction.getPrimaryText(null).toString());
}
}).addOnFailureListener((exception) -> {
if (exception instanceof ApiException) {
ApiException apiException = (ApiException) exception;
Log.e(TAG, "Place not found: " + apiException.getStatusCode());
}
});
Сеансовые токены
Токены сеанса группируют фазы запроса и выбора пользовательского поиска в отдельный сеанс для выставления счетов. Мы рекомендуем использовать токены сеанса для всех сеансов автозаполнения. Сеанс начинается, когда пользователь начинает вводить запрос, и заканчивается, когда он выбирает место. Каждый сеанс может иметь несколько запросов, за которыми следует один выбор места. После завершения сеанса токен больше не действителен; ваше приложение должно генерировать новый токен для каждого сеанса.
Полевые маски
В методах, которые возвращают данные о месте, необходимо указать, какие типы данных о месте возвращать с каждым запросом. Это помогает гарантировать, что вы запрашиваете (и платите за) только те данные, которые вы действительно будете использовать.
Чтобы указать, какие типы данных следует возвращать, передайте массив Place.Field
в FetchPlaceRequest
, как показано в следующем примере:
// Include address, ID, and phone number.
List<Place.Field> placeFields = Arrays.asList(Place.Field.FORMATTED_ADDRESS,
Place.Field.ID,
Place.Field.INTERNATIONAL_PHONE_NUMBER);
Список полей, которые можно использовать в маске поля, см. в разделе Размещение полей данных (новое) .
Узнайте больше о товарных знаках Places Data .
Обновления выбора места и автозаполнения
В этом разделе описываются изменения в виджетах «Места» (выбор места и автозаполнение).
Программное автозаполнение
В автозаполнение были внесены следующие изменения:
-
PlaceAutocomplete
переименован вAutocomplete
.-
PlaceAutocomplete.getPlace
переименован вAutocomplete.getPlaceFromIntent
. -
PlaceAutocomplete.getStatus
переименован вAutocomplete.getStatusFromIntent
.
-
-
PlaceAutocomplete.RESULT_ERROR
переименован вAutocompleteActivity.RESULT_ERROR
(обработка ошибок для фрагмента автозаполнения НЕ изменилась).
Место выбора
Place Picker устарел 29 января 2019 года. Он был отключен 29 июля 2019 года и больше не доступен. Продолжение использования приведет к сообщению об ошибке. Новый SDK не поддерживает Place Picker.
Виджеты автозаполнения
Обновлены виджеты автозаполнения:
- Префикс
Place
был удален из всех классов. - Добавлена поддержка токенов сеанса. Виджет управляет токенами автоматически в фоновом режиме.
- Добавлена поддержка масок полей, которые позволяют выбирать, какие типы данных о местах возвращать после того, как пользователь сделает выбор.
В следующих разделах показано, как добавить виджет автозаполнения в ваш проект.
Встроить AutocompleteFragment
Чтобы добавить фрагмент автозаполнения, выполните следующие действия:
Добавьте фрагмент в XML-макет вашей активности, как показано в следующем примере.
<fragment android:id="@+id/autocomplete_fragment" android:layout_width="match_parent" android:layout_height="wrap_content" android:name= "com.google.android.libraries.places.widget.AutocompleteSupportFragment" />
Чтобы добавить виджет автозаполнения в действие, выполните следующие действия:
- Инициализируйте
Places
, передав контекст приложения и ваш ключ API. - Инициализируйте
AutocompleteSupportFragment
. - Вызовите
setPlaceFields()
чтобы указать типы данных о месте, которые вы хотите получить. - Добавьте
PlaceSelectionListener
, чтобы что-то сделать с результатом, а также обработать любые возможные ошибки.
В следующем примере показано добавление виджета автозаполнения к действию:
/** * Initialize Places. For simplicity, the API key is hard-coded. In a production * environment we recommend using a secure mechanism to manage API keys. */ if (!Places.isInitialized()) { Places.initialize(getApplicationContext(), "YOUR_API_KEY"); } // Initialize the AutocompleteSupportFragment. AutocompleteSupportFragment autocompleteFragment = (AutocompleteSupportFragment) getSupportFragmentManager().findFragmentById(R.id.autocomplete_fragment); autocompleteFragment.setPlaceFields(Arrays.asList(Place.Field.ID, Place.Field.DISPLAY_NAME)); autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() { @Override public void onPlaceSelected(Place place) { // TODO: Get info about the selected place. Log.i(TAG, "Place: " + place.getName() + ", " + place.getId()); } @Override public void onError(Status status) { // TODO: Handle the error. Log.i(TAG, "An error occurred: " + status); } });
- Инициализируйте
Используйте намерение для запуска действия автозаполнения
- Инициализируйте
Places
, передав контекст приложения и ваш ключ API - Используйте
Autocomplete.IntentBuilder
для создания намерения, передавая желаемый режимPlaceAutocomplete
(полноэкранный или наложение). Намерение должно вызыватьstartActivityForResult
, передавая код запроса, который идентифицирует ваше намерение. - Переопределите обратный вызов
onActivityResult
для получения выбранного места.
В следующем примере показано, как использовать намерение для запуска автозаполнения, а затем обработать результат:
/**
* Initialize Places. For simplicity, the API key is hard-coded. In a production
* environment we recommend using a secure mechanism to manage API keys.
*/
if (!Places.isInitialized()) {
Places.initialize(getApplicationContext(), "YOUR_API_KEY");
}
...
// Set the fields to specify which types of place data to return.
List<Place.Field> fields = Arrays.asList(Place.Field.ID, Place.Field.DISPLAY_NAME);
// Start the autocomplete intent.
Intent intent = new Autocomplete.IntentBuilder(
AutocompleteActivityMode.FULLSCREEN, fields)
.build(this);
startActivityForResult(intent, AUTOCOMPLETE_REQUEST_CODE);
...
/**
* Override the activity's onActivityResult(), check the request code, and
* do something with the returned place data (in this example its place name and place ID).
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == AUTOCOMPLETE_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
Place place = Autocomplete.getPlaceFromIntent(data);
Log.i(TAG, "Place: " + place.getName() + ", " + place.getId());
} else if (resultCode == AutocompleteActivity.RESULT_ERROR) {
// TODO: Handle the error.
Status status = Autocomplete.getStatusFromIntent(data);
Log.i(TAG, status.getStatusMessage());
} else if (resultCode == RESULT_CANCELED) {
// The user canceled the operation.
}
}
}
Place Picker больше не доступен
Place Picker устарел 29 января 2019 года. Он был отключен 29 июля 2019 года и больше не доступен. Продолжение использования приведет к сообщению об ошибке. Новый SDK не поддерживает Place Picker.