W tym przewodniku wyjaśniamy różnice między biblioteką zgodności Places a nową samodzielną wersją pakietu Places SDK na Androida. Jeśli zamiast przejść na nową samodzielną wersję pakietu Places SDK na Androida używasz biblioteki zgodności Places, ten przewodnik pokaże Ci, jak zaktualizować projekty, aby korzystać z nowej wersji pakietu Places SDK na Androida.
Jedynym sposobem na uzyskanie dostępu do funkcji i poprawek błędów w pakiecie SDK Miejsc na Androida w wersji powyżej 2.6.0 jest korzystanie z pakietu SDK Miejsc na Androida. Zalecamy jak najszybsze przejście z biblioteki zgodności na nową wersję pakietu Places SDK na Androida.
Błąd: 9005 PLACES_API_RATE_LIMIT_EXCEEDED
Co się zmieniło?
Główne obszary zmian to:
- Nowa wersja pakietu SDK Miejsc na Androida jest rozpowszechniana jako statyczna biblioteka klienta. Przed styczniem 2019 r. pakiet SDK Miejsc na Androida był dostępny w Usługach Google Play. Od tego czasu udostępniliśmy bibliotekę zgodności Miejsc, aby ułatwić przejście na nowy pakiet Places SDK na Androida.
- Są zupełnie nowe metody.
- W przypadku metod zwracających szczegóły miejsca obsługiwane są teraz maski pól. Za pomocą masek pól możesz określić, jakie typy danych o miejscu mają być zwracane.
- Ulepszyliśmy kody stanu używane do zgłaszania błędów.
- Autouzupełnianie obsługuje teraz tokeny sesji.
- Selektor miejsc nie jest już dostępny.
Informacje o bibliotece zgodności Miejsc
W styczniu 2019 r. wraz z wersją 1.0 samodzielnego pakietu SDK Miejsc na Androida Google udostępnił bibliotekę zgodności, która ułatwia migrację z wycofanej wersji pakietu SDK Miejsc na Androida w Usługach Google Play (com.google.android.gms:play-services-places
).
Ta biblioteka zgodności została udostępniona tymczasowo, aby przekierowywać i tłumaczyć wywołania interfejsu API kierowane do wersji Usług Google Play na nową wersję samodzielną, dopóki deweloperzy nie będą mogli przenieść kodu, aby używać nowych nazw w samodzielnym pakiecie SDK. Dla każdej wersji pakietu SDK Miejsc na Androida wydanej od wersji 1.0 do wersji 2.6.0 została udostępniona odpowiednia wersja biblioteki zgodności Miejsc, która zapewnia równoważną funkcjonalność.
Wstrzymanie i wycofanie biblioteki zgodności Miejsc
Wszystkie wersje biblioteki zgodności pakietu SDK Miejsc na Androida zostały wycofane 31 marca 2022 r. Wersja 2.6.0 to ostatnia wersja biblioteki zgodności Miejsc. Jedynym sposobem na dostęp do funkcji i poprawek błędów w pakiecie SDK Miejsc na Androida w wersji powyżej 2.6.0 jest korzystanie z pakietu SDK Miejsc na Androida.
Aby uzyskać dostęp do nowych funkcji i ważnych poprawek błędów w wersjach powyżej 2.6.0, zalecamy przejście na pakiet Places SDK na Androida. Jeśli obecnie korzystasz z biblioteki zgodności, wykonaj czynności opisane w sekcji Instalowanie pakietu SDK Miejsc na Androida, aby przejść na pakiet SDK Miejsc na Androida.
Instalowanie biblioteki klienta
Nowa wersja pakietu SDK Miejsc na Androida jest rozpowszechniana jako statyczna biblioteka klienta.
Aby dodać pakiet Places SDK na Androida do projektu Android Studio, użyj Maven:
Jeśli obecnie korzystasz z biblioteki zgodności Miejsc:
Zastąp ten wiersz w sekcji
dependencies
:implementation 'com.google.android.libraries.places:places-compat:X.Y.Z'
Aby przejść na pakiet SDK Miejsc na Androida, użyj tego wiersza:
implementation("com.google.android.libraries.places:places:4.3.1")
Jeśli obecnie używasz wersji pakietu SDK Miejsc na Androida w Usługach Play:
Zastąp ten wiersz w sekcji
dependencies
:implementation 'com.google.android.gms:play-services-places:X.Y.Z'
Aby przejść na pakiet SDK Miejsc na Androida, użyj tego wiersza:
implementation("com.google.android.libraries.places:places:4.3.1")
Zsynchronizuj projekt Gradle.
Ustaw wartość
minSdkVersion
w projekcie aplikacji na 23 lub wyższą.Zaktualizuj komponenty „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
Skompiluj aplikację. Jeśli podczas kompilacji wystąpią błędy spowodowane przejściem na pakiet Places SDK na Androida, zapoznaj się z sekcjami poniżej, aby dowiedzieć się, jak je rozwiązać.
Inicjowanie nowego klienta pakietu Places SDK
Zainicjuj nowego klienta pakietu SDK Miejsc, jak pokazano w tym przykładzie:
// 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);
Kody stanu
Zmieniliśmy kod stanu błędów związanych z limitem zapytań na sekundę. Błędy limitu zapytań są teraz zwracane za pomocą PlaceStatusCodes.OVER_QUERY_LIMIT
. Nie ma już limitów QPD.
Dodano te kody stanu:
REQUEST_DENIED
– prośba została odrzucona. Możliwe przyczyny:- Nie podano klucza interfejsu API.
- Podano nieprawidłowy klucz interfejsu API.
- Interfejs Places API nie został włączony w konsoli Cloud.
- Podano klucz interfejsu API z nieprawidłowymi ograniczeniami.
INVALID_REQUEST
– żądanie jest nieprawidłowe z powodu brakującego lub nieprawidłowego argumentu.NOT_FOUND
– nie znaleziono wyników dla danego żądania.
Nowe metody
Nowa wersja pakietu SDK Miejsc na Androida zawiera zupełnie nowe metody, które zostały zaprojektowane z myślą o spójności. Wszystkie nowe metody są zgodne z tymi zasadami:
- Punkty końcowe nie używają już czasownika
get
. - Obiekty żądań i odpowiedzi mają taką samą nazwę jak odpowiednia metoda klienta.
- Obiekty żądań mają teraz konstruktory. Wymagane parametry są przekazywane jako parametry konstruktora żądania.
- Bufory nie są już używane.
W tej sekcji przedstawiamy nowe metody i wyjaśniamy, jak działają.
Pobieranie miejsca według identyfikatora
Użyj fetchPlace()
, aby uzyskać szczegółowe informacje o konkretnym miejscu. fetchPlace()
działa podobnie do getPlaceById()
.
Aby pobrać miejsce, wykonaj te czynności:
Wywołaj metodę
fetchPlace()
, przekazując obiektFetchPlaceRequest
, który określa identyfikator miejsca i listę pól określających dane miejsca do zwrócenia.// 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();
Zadzwoń pod numer
addOnSuccessListener()
, aby rozwiązać problemFetchPlaceResponse
. Zwracany jest pojedynczy wynikPlace
.// 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()); } });
Pobieranie zdjęcia miejsca
Użyj fetchPhoto()
, aby pobrać zdjęcie miejsca. fetchPhoto()
zwraca zdjęcia miejsca. Uprościliśmy wzorzec
prośby o zdjęcie. Możesz teraz wysyłać żądania PhotoMetadata
bezpośrednio z obiektu Place
. Nie jest już potrzebne osobne żądanie.
Zdjęcia mogą mieć maksymalną szerokość lub wysokość 1600 pikseli. fetchPhoto()
działa podobnie do getPhoto()
.
Aby pobrać zdjęcia miejsca:
Ustaw połączenie z numerem
fetchPlace()
. Pamiętaj, aby w prośbie uwzględnić polePHOTO_METADATAS
:List<Place.Field> fields = Arrays.asList(Place.Field.PHOTO_METADATAS);
Pobierz obiekt Place (w tym przykładzie użyto
fetchPlace()
, ale możesz też użyćfindCurrentPlace()
):FetchPlaceRequest placeRequest = FetchPlaceRequest.builder(placeId, fields).build();
Dodaj
OnSuccessListener
, aby pobrać metadane zdjęcia z wynikowego elementuPlace
wFetchPlaceResponse
, a następnie użyj tych metadanych, aby pobrać bitmapę i tekst z informacjami o autorze: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()); } }); });
Znajdowanie miejsca na podstawie lokalizacji użytkownika
Użyj findCurrentPlace()
, aby znaleźć bieżącą lokalizację urządzenia użytkownika. findCurrentPlace()
zwraca listę PlaceLikelihood
s wskazujących miejsca, w których urządzenie użytkownika
najprawdopodobniej się znajduje. findCurrentPlace()
działa podobnie do getCurrentPlace()
.
Aby uzyskać aktualną lokalizację urządzenia użytkownika, wykonaj te czynności:
Upewnij się, że aplikacja prosi o uprawnienia
ACCESS_FINE_LOCATION
iACCESS_WIFI_STATE
. Użytkownik musi zezwolić na dostęp do lokalizacji bieżącego urządzenia. Szczegółowe informacje znajdziesz w sekcji Request App Permissions (Prośba o uprawnienia aplikacji).Utwórz
FindCurrentPlaceRequest
, w tym listę typów danych o miejscach do zwrócenia.// 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();
Wywołaj funkcję findCurrentPlace i obsłuż odpowiedź, sprawdzając najpierw, czy użytkownik przyznał uprawnienia do korzystania z lokalizacji urządzenia.
// 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(); }
Znajdowanie podpowiedzi autouzupełniania
Użyj findAutocompletePredictions()
, aby zwracać prognozy miejsc w odpowiedzi na zapytania użytkownika.
findAutocompletePredictions()
działa podobnie do getAutocompletePredictions()
.
Poniższy przykład pokazuje wywołanie funkcji 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());
}
});
Tokeny sesji
Tokeny sesji grupują fazy zapytania i wyboru wyszukiwania użytkownika w osobną sesję na potrzeby rozliczeń. W przypadku wszystkich sesji autouzupełniania zalecamy używanie tokenów sesji. Sesja rozpoczyna się, gdy użytkownik zaczyna wpisywać zapytanie, a kończy, gdy wybierze miejsce. Każda sesja może zawierać wiele zapytań, po których następuje wybór jednego miejsca. Po zakończeniu sesji token traci ważność. Aplikacja musi generować nowy token dla każdej sesji.
Maski pól
W metodach, które zwracają szczegóły miejsca, musisz określić, jakie typy danych o miejscu mają być zwracane w odpowiedzi na każde żądanie. Dzięki temu masz pewność, że prosisz tylko o dane, których będziesz używać, i za nie płacisz.
Aby określić, które typy danych mają być zwracane, przekaż tablicę Place.Field
w FetchPlaceRequest
, jak pokazano w tym przykładzie:
// Include address, ID, and phone number.
List<Place.Field> placeFields = Arrays.asList(Place.Field.FORMATTED_ADDRESS,
Place.Field.ID,
Place.Field.INTERNATIONAL_PHONE_NUMBER);
Listę pól, których możesz używać w masce pól, znajdziesz w artykule Pola danych o miejscach (nowe) .
Dowiedz się więcej o kodach SKU danych o miejscach.
Aktualizacje selektora miejsc i autouzupełniania
W tej sekcji opisujemy zmiany w widżetach Miejsc (selektorze miejsca i autouzupełnianiu).
Automatyzacja autouzupełniania
W autouzupełnianiu wprowadzono te zmiany:
- Nazwa
PlaceAutocomplete
została zmieniona naAutocomplete
.- Nazwa
PlaceAutocomplete.getPlace
została zmieniona naAutocomplete.getPlaceFromIntent
. - Nazwa
PlaceAutocomplete.getStatus
została zmieniona naAutocomplete.getStatusFromIntent
.
- Nazwa
PlaceAutocomplete.RESULT_ERROR
zmienia nazwę naAutocompleteActivity.RESULT_ERROR
(obsługa błędów w fragmencie autouzupełniania NIE uległa zmianie).
Selektor miejsca
Selektor miejsc został wycofany 29 stycznia 2019 roku. Została wyłączona 29 lipca 2019 roku i nie jest już dostępna. Dalsze korzystanie z tej funkcji spowoduje wyświetlenie komunikatu o błędzie. Nowy pakiet SDK nie obsługuje selektora miejsc.
Widżety autouzupełniania
Widżety autouzupełniania zostały zaktualizowane:
- Prefiks
Place
został usunięty ze wszystkich zajęć. - Dodaliśmy obsługę tokenów sesji. Widżet automatycznie zarządza tokenami w tle.
- Dodano obsługę masek pól, które umożliwiają wybór typów danych o miejscu, jakie mają być zwracane po dokonaniu wyboru przez użytkownika.
Z sekcji poniżej dowiesz się, jak dodać do projektu widżet autouzupełniania.
Umieszczanie AutocompleteFragment
Aby dodać fragment autouzupełniania, wykonaj te czynności:
Dodaj fragment do układu XML aktywności, jak pokazano w tym przykładzie.
<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" />
Aby dodać widżet autouzupełniania do aktywności, wykonaj te czynności:
- Zainicjuj
Places
, przekazując kontekst aplikacji i klucz interfejsu API. - Zainicjuj obiekt
AutocompleteSupportFragment
. - Wywołaj
setPlaceFields()
, aby wskazać typy danych o miejscach, które chcesz uzyskać. - Dodaj
PlaceSelectionListener
, aby wykonać działanie na wyniku, a także obsłużyć wszelkie błędy, które mogą wystąpić.
Poniższy przykład pokazuje, jak dodać widżet autouzupełniania do aktywności:
/** * 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); } });
- Zainicjuj
Używanie intencji do uruchamiania działania autouzupełniania
- Zainicjuj
Places
, przekazując kontekst aplikacji i klucz interfejsu API. - Użyj
Autocomplete.IntentBuilder
, aby utworzyć intencję, przekazując żądanyPlaceAutocomplete
tryb (pełnoekranowy lub nakładka). Intencja musi wywoływać metodęstartActivityForResult
, przekazując kod żądania, który identyfikuje Twoją intencję. - Zastąp wywołanie zwrotne
onActivityResult
, aby otrzymać wybrane miejsce.
Ten przykład pokazuje, jak użyć intencji do uruchomienia autouzupełniania, a następnie przetworzyć wynik:
/**
* 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.
}
}
}
Selektor miejsc nie jest już dostępny
Selektor miejsc został wycofany 29 stycznia 2019 roku. Została wyłączona 29 lipca 2019 roku i nie jest już dostępna. Dalsze korzystanie z tej funkcji spowoduje wyświetlenie komunikatu o błędzie. Nowy pakiet SDK nie obsługuje selektora miejsc.