W tym przewodniku wyjaśniamy różnice między biblioteką zgodności Places a nową samodzielną wersją Places SDK na Androida. Jeśli zamiast migracji do nowej samodzielnej wersji pakietu Places SDK na Androida używasz biblioteki kompatybilności z Places, w tym przewodniku znajdziesz informacje o tym, jak zaktualizować projekty, aby używać nowej wersji pakietu Places SDK na Androida.
Jedynym sposobem na dostęp do funkcji i poprawek błędów w pakiecie SDK Miejsc na Androida w wersji 2.6.0 lub nowszej jest użycie pakietu SDK Miejsc na Androida. Google zaleca jak najszybsze przejście z biblioteki zgodności na nową wersję pakietu SDK Map na Androida.
Co się zmieniło?
Główne obszary zmian to:
- Nowa wersja pakietu SDK Miejsca na Androida jest rozpowszechniana jako statyczna biblioteka klienta. Przed styczniem 2019 r. pakiet SDK Miejsca na Androida był dostępny za pośrednictwem Usług Google Play. Od tego czasu udostępniliśmy bibliotekę zgodności z Places, aby ułatwić przejście na nowy pakiet SDK Miejsc na Androida.
- Dostępne są całkowicie nowe metody.
- Maski pól są teraz obsługiwane w przypadku metod zwracających szczegóły miejsca. Za pomocą masek pól możesz określić, jakie typy danych o miejscach mają być zwracane.
- Ulepszono kody stanu używane do zgłaszania błędów.
- Autouzupełnianie obsługuje teraz tokeny sesji.
- Wybór miejsca nie jest już dostępny.
Biblioteka zgodności z Google Places
W styczniu 2019 r., wraz z wydaniem wersji 1.0 samodzielnego pakietu SDK Miejsca na Androida, Google udostępniło bibliotekę zgodności, która ułatwia migrację z wersji pakietu SDK Miejsca na Androida w Usługach Google Play (com.google.android.gms:play-services-places
).
Ta biblioteka zgodności została tymczasowo udostępniona, 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 na wersję samodzielną pakietu SDK, aby używać nowych nazw. W przypadku każdej wersji pakietu SDK Miejsca na Androida od wersji 1.0 do 2.6.0 została wydana odpowiednia wersja biblioteki zgodności z Miejscami, która zapewnia równoważną funkcjonalność.
Zamrożenie i wycofanie biblioteki kompatybilności z Miejscami
Wszystkie wersje biblioteki zgodności pakietu SDK Miejsca na Androida zostały wycofane 31 marca 2022 r. Wersja 2.6.0 jest ostatnią wersją biblioteki zgodności z Google Places. Jedynym sposobem na dostęp do funkcji i poprawek błędów w pakiecie SDK Miejsc na Androida w wersji 2.6.0 lub nowszej jest użycie pakietu SDK Miejsc na Androida.
Google zaleca przejście na pakiet Places SDK na Androida, aby uzyskać dostęp do nowych funkcji i krytycznych poprawek błędów w wersjach wyższych niż 2.6.0. Jeśli obecnie używasz biblioteki zgodności, wykonaj czynności opisane w sekcji Instalowanie pakietu SDK Miejsca na Androida, aby przejść na pakiet SDK Miejsca na Androida.
Instalowanie biblioteki klienta
Nowa wersja pakietu SDK Miejsca na Androida jest rozpowszechniana jako statyczna biblioteka klienta.
Aby dodać pakiet SDK Miejsc na Androida do projektu w Android Studio, użyj Mavena:
Jeśli obecnie korzystasz z biblioteki zgodności Places:
W sekcji
dependencies
zastąp ten wiersz: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:3.3.0'
Jeśli obecnie używasz wersji pakietu SDK Miejsca na Androida z Usługami Google Play:
W sekcji
dependencies
zastąp ten wiersz: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:3.3.0'
Zsynchronizuj projekt Gradle.
Ustaw wartość
minSdkVersion
dla projektu aplikacji na 16 lub wyższą.Zaktualizuj zasoby „Technologia 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
Utwórz aplikację. Jeśli w wyniku konwersji na pakiet Places SDK dla Androida pojawią się błędy kompilacji, zapoznaj się z sekcjami poniżej, aby dowiedzieć się, jak je rozwiązać.
Inicjowanie nowego klienta pakietu SDK Places
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
Zmienił się kod stanu błędów związanych z limitami QPS. Błędy związane z limitem zapytań są teraz zwracane za pomocą PlaceStatusCodes.OVER_QUERY_LIMIT
. Nie ma już limitów dotyczących QPD.
Dodano te kody stanu:
REQUEST_DENIED
– prośba została odrzucona. Możliwe przyczyny:- Nie podano klucza 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 braku lub nieprawidłowego argumentu.NOT_FOUND
– nie znaleziono żadnych wyników dla danego żądania.
Nowe metody
Nowa wersja pakietu SDK Miejsc na Androida wprowadza zupełnie nowe metody, które zostały zaprojektowane w celu zapewnienia spójności. Wszystkie nowe metody:
- Punkty końcowe nie używają już czasownika
get
. - Obiekty żądań i odpowiedzi mają tę samą nazwę co odpowiadająca im metoda klienta.
- Obiekty żądań mają teraz konstruktory; wymagane parametry są przekazywane jako parametry konstruktora żądania.
- Bufory nie są już używane.
W tej sekcji opisujemy nowe metody i wyjaśniamy, jak działają.
Pobieranie miejsca według identyfikatora
Aby uzyskać szczegółowe informacje o konkretnym miejscu, użyj fetchPlace()
. fetchPlace()
działa podobnie jak getPlaceById()
.
Aby pobrać dane o miejscu:
Wywołaj funkcję
fetchPlace()
, przekazując obiektFetchPlaceRequest
określający identyfikator miejsca oraz listę pol określających dane miejsca, które mają zostać zwrócone.// 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 1Place
wynik.// 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 uzyskać zdjęcie miejsca. fetchPhoto()
zwraca zdjęcia miejsca. Uproszczony został schemat przesyłania prośby o zrobienie zdjęcia. Teraz możesz poprosić o PhotoMetadata
bezpośrednio z obiektu Place
. Nie musisz już wysyłać osobnej prośby.
Zdjęcia mogą mieć maksymalną szerokość lub wysokość 1600 pikseli. Funkcja fetchPhoto()
działa podobnie do funkcji getPhoto()
.
Aby pobrać zdjęcia miejsca:
Zaplanuj połączenie z numerem
fetchPlace()
. Pamiętaj, aby w prośbie podać polePHOTO_METADATAS
:List<Place.Field> fields = Arrays.asList(Place.Field.PHOTO_METADATAS);
Pobierz obiekt Miejsce (w tym przykładzie używamy obiektu
fetchPlace()
, ale możesz też użyć obiektufindCurrentPlace()
):FetchPlaceRequest placeRequest = FetchPlaceRequest.builder(placeId, fields).build();
Dodaj
OnSuccessListener
, aby uzyskać metadane zdjęcia z wynikającegoPlace
wFetchPlaceResponse
, a następnie użyj otrzymanych metadanych, aby uzyskać bitmapę i tekst atrybucji: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
, która wskazuje miejsca, w których urządzenie użytkownika znajduje się najprawdopodobniej. findCurrentPlace()
działa podobnie jak getCurrentPlace()
.
Aby uzyskać aktualną lokalizację urządzenia użytkownika:
Upewnij się, że aplikacja prosi o uprawnienia
ACCESS_FINE_LOCATION
iACCESS_WIFI_STATE
. Użytkownik musi zezwolić na dostęp do bieżącej lokalizacji urządzenia. Więcej informacji znajdziesz w artykule 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();
Zawołaj findCurrentPlace i obsługuj odpowiedź, najpierw sprawdzając, czy użytkownik zezwolił na korzystanie 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 parametru findAutocompletePredictions()
, aby zwracać prognozy miejsc w odpowiedzi na zapytania użytkownika.
findAutocompletePredictions()
działa podobnie jak 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
Na potrzeby rozliczeń tokeny sesji grupowały fazy zapytania i wyboru w ramach pojedynczej sesji. Zalecamy używanie tokenów sesji we wszystkich sesjach autouzupełniania. Sesja rozpoczyna się, gdy użytkownik zacznie 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 wygenerować nowy token na każdą sesję.
Maski pól
W metodach, które zwracają szczegóły miejsca, musisz określić, jakie typy danych o miejscu mają być zwracane w ramach każdego żądania. Dzięki temu będziesz prosić o dane (i płacić za nie) tylko wtedy, gdy faktycznie ich potrzebujesz.
Aby określić, które typy danych mają być zwracane, prześlij tablicę Place.Field
w parametry funkcji 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 (nowa wersja) .
Dowiedz się więcej o kodach SKU danych o miejscach.
Aktualizacje selektora miejsc i autouzupełniania
W tej sekcji opisujemy zmiany w widżetach Miejsca (wybieranie miejsc i autouzupełnianie).
Automatyczne autouzupełnianie
W sekcji autouzupełnianie 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
- Nazwa
PlaceAutocomplete.RESULT_ERROR
została zmieniona naAutocompleteActivity.RESULT_ERROR
(obsługa błędów w fragmentie autouzupełniania się nie zmieniła).
Selektor miejsc
Selektor miejsc został wycofany 29 stycznia 2019 r. Został on wyłączony 29 lipca 2019 r. i nie jest już dostępny. Dalsze korzystanie z tego adresu 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:
- Prefix
Place
został usunięty ze wszystkich klas. - Dodaliśmy obsługę tokenów sesji. Widget automatycznie zarządza tokenami w tle.
- Dodano obsługę masek pól, które umożliwiają wybranie typów danych o miejscach, które mają być zwracane po dokonaniu przez użytkownika wyboru.
W następnych sekcjach dowiesz się, jak dodać do projektu widżet autouzupełniania.
Umieść AutocompleteFragment
Aby dodać fragment autouzupełniania:
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. - Inicjalizacja
AutocompleteSupportFragment
. - Wybierz
setPlaceFields()
, aby wskazać typy danych o miejscach, które chcesz pobrać. - Dodaj element
PlaceSelectionListener
, aby wykonać jakąś operację na wyniku, a także obsłużyć ewentualne błędy.
Ten przykład pokazuje dodawanie widżetu 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
- Inicjuj
Places
, przekazując kontekst aplikacji i klucz API - Użyj elementu
Autocomplete.IntentBuilder
, aby utworzyć intencję, przekazując żądany trybPlaceAutocomplete
(pełnoekranowy lub nakładka). Intencją musi być wywołaniestartActivityForResult
z przekazanym kodem żądania, który identyfikuje intencję. - Zastąpić wywołanie zwrotne
onActivityResult
, aby otrzymać wybrane miejsce.
Z tego przykładu dowiesz się, jak użyć intencji do uruchomienia automatycznego uzupełniania, a potem 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 r. Został on wyłączony 29 lipca 2019 r. i nie jest już dostępny. Dalsze korzystanie z tego adresu e-mail spowoduje wyświetlenie komunikatu o błędzie. Nowy pakiet SDK nie obsługuje selektora miejsc.