Di chuyển sang ứng dụng SDK Địa điểm mới

Nhà phát triển ở Khu vực kinh tế Châu Âu (EEA)

Hướng dẫn này giải thích những thay đổi giữa thư viện tương thích Places và phiên bản độc lập mới của Places SDK for Android. Nếu bạn đang sử dụng thư viện tương thích Places thay vì di chuyển sang phiên bản độc lập mới của Places SDK cho Android, thì hướng dẫn này sẽ cho bạn biết cách cập nhật các dự án để sử dụng phiên bản mới của Places SDK cho Android.

Cách duy nhất để truy cập vào các tính năng và bản sửa lỗi trong Places SDK for Android từ phiên bản 2.6.0 trở lên là sử dụng Places SDK for Android. Google khuyên bạn nên cập nhật từ thư viện tương thích lên phiên bản Places SDK for Android mới càng sớm càng tốt.

Lỗi: 9005 PLACES_API_RATE_LIMIT_EXCEEDED

Điều gì đã thay đổi?

Sau đây là những thay đổi chính:

  • Phiên bản mới của Places SDK for Android được phân phối dưới dạng một thư viện ứng dụng tĩnh. Trước tháng 1 năm 2019, Places SDK for Android được cung cấp thông qua Dịch vụ Google Play. Kể từ đó, một thư viện tương thích với Places đã được cung cấp để giúp quá trình chuyển đổi sang Places SDK mới cho Android diễn ra dễ dàng hơn.
  • các phương thức hoàn toàn mới.
  • Hiện tại, mặt nạ trường được hỗ trợ cho các phương thức trả về thông tin chi tiết về địa điểm. Bạn có thể sử dụng mặt nạ trường để chỉ định những loại dữ liệu về địa điểm cần trả về.
  • Chúng tôi đã cải thiện mã trạng thái dùng để báo cáo lỗi.
  • Tính năng tự động hoàn thành hiện hỗ trợ mã thông báo phiên.
  • Công cụ chọn địa điểm không còn hoạt động nữa.

Giới thiệu về thư viện tương thích Places

Vào tháng 1 năm 2019, khi phát hành phiên bản 1.0 của Places SDK độc lập cho Android, Google đã cung cấp một thư viện tương thích để hỗ trợ việc di chuyển từ phiên bản Google Play Services đã ngừng hoạt động của Places SDK cho Android (com.google.android.gms:play-services-places).

Thư viện tương thích này được cung cấp tạm thời để chuyển hướng và dịch các lệnh gọi API nhắm đến phiên bản Các dịch vụ của Google Play sang phiên bản độc lập mới cho đến khi nhà phát triển có thể di chuyển mã của họ để sử dụng tên mới trong SDK độc lập. Đối với mỗi phiên bản Places SDK for Android được phát hành từ phiên bản 1.0 đến phiên bản 2.6.0, một phiên bản tương ứng của thư viện tương thích Places cũng được phát hành để cung cấp chức năng tương đương.

Đóng băng và ngừng sử dụng thư viện tương thích Places

Tất cả các phiên bản của thư viện tương thích cho Places SDK for Android đều không được dùng nữa kể từ ngày 31 tháng 3 năm 2022. Phiên bản 2.6.0 là phiên bản mới nhất của thư viện tương thích Places. Cách duy nhất để truy cập vào các tính năng và bản sửa lỗi trong Places SDK for Android từ phiên bản 2.6.0 trở lên là sử dụng Places SDK for Android.

Google khuyến nghị bạn di chuyển sang Places SDK cho Android để truy cập các tính năng mới và bản sửa lỗi quan trọng cho các bản phát hành trên Phiên bản 2.6.0. Nếu bạn hiện đang sử dụng thư viện tương thích, hãy làm theo các bước bên dưới trong phần Cài đặt Places SDK cho Android để di chuyển sang Places SDK cho Android.

Cài đặt thư viện ứng dụng

Phiên bản mới của Places SDK for Android được phân phối dưới dạng một thư viện ứng dụng tĩnh.

Sử dụng Maven để thêm Places SDK for Android vào dự án Android Studio:

  1. Nếu bạn hiện đang sử dụng thư viện tương thích Places:

    1. Thay thế dòng sau trong phần dependencies:

          implementation 'com.google.android.libraries.places:places-compat:X.Y.Z'

      Với dòng này, bạn có thể chuyển sang Places SDK for Android:

          implementation("com.google.android.libraries.places:places:4.3.1")

  2. Nếu bạn hiện đang sử dụng phiên bản Places SDK cho Android của Dịch vụ Play:

    1. Thay thế dòng sau trong phần dependencies:

          implementation 'com.google.android.gms:play-services-places:X.Y.Z'

      Với dòng này, bạn có thể chuyển sang Places SDK for Android:

          implementation("com.google.android.libraries.places:places:4.3.1")

  3. Đồng bộ hoá dự án Gradle.

  4. Đặt minSdkVersion cho dự án ứng dụng của bạn thành 23 trở lên.

  5. Cập nhật các thành phần "Được cung cấp bởi 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
  6. Tạo ứng dụng. Nếu bạn thấy bất kỳ lỗi nào trong quá trình tạo do việc chuyển đổi sang Places SDK cho Android, hãy xem các phần bên dưới để biết thông tin về cách giải quyết những lỗi này.

Khởi chạy ứng dụng Places SDK mới

Khởi chạy ứng dụng Places SDK mới như trong ví dụ sau:

// 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);

Mã trạng thái

Mã trạng thái cho lỗi giới hạn QPS đã thay đổi. Giờ đây, các lỗi giới hạn QPS sẽ được trả về thông qua PlaceStatusCodes.OVER_QUERY_LIMIT. Không còn giới hạn về QPD nữa.

Chúng tôi đã thêm các mã trạng thái sau:

  • REQUEST_DENIED – Yêu cầu đã bị từ chối. Nguyên nhân dẫn đến sự khác biệt này có thể là:

    • Bạn chưa cung cấp khoá API.
    • Bạn đã cung cấp một khoá API không hợp lệ.
    • Bạn chưa bật Places API trong Cloud Console.
    • Khoá API được cung cấp có các quy tắc hạn chế không chính xác đối với khoá.
  • INVALID_REQUEST – Yêu cầu không hợp lệ do thiếu hoặc có đối số không hợp lệ.

  • NOT_FOUND – Không tìm thấy kết quả nào cho yêu cầu đã cho.

Phương thức mới

Phiên bản mới của Places SDK for Android giới thiệu các phương thức hoàn toàn mới được thiết kế để đảm bảo tính nhất quán. Tất cả các phương thức mới đều tuân thủ những điều sau:

  • Các điểm cuối không còn sử dụng động từ get nữa.
  • Các đối tượng yêu cầu và phản hồi có cùng tên với phương thức tương ứng của ứng dụng.
  • Các đối tượng yêu cầu hiện có trình tạo; các tham số bắt buộc được truyền dưới dạng tham số trình tạo yêu cầu.
  • Không còn sử dụng vùng đệm.

Phần này giới thiệu các phương thức mới và cho bạn biết cách chúng hoạt động.

Tìm nạp một địa điểm theo mã nhận dạng

Sử dụng fetchPlace() để xem thông tin chi tiết về một địa điểm cụ thể. fetchPlace() hoạt động tương tự như getPlaceById().

Hãy làm theo các bước sau để tìm nạp một địa điểm:

  1. Gọi fetchPlace(), truyền một đối tượng FetchPlaceRequest chỉ định một Mã địa điểm và danh sách các trường chỉ định dữ liệu Địa điểm cần trả về.

    // 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();
    
    
  2. Gọi addOnSuccessListener() để xử lý FetchPlaceResponse. Một kết quả Place duy nhất sẽ được trả về.

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

Tìm nạp ảnh về một địa điểm

Sử dụng fetchPhoto() để lấy ảnh địa điểm. fetchPhoto() trả về ảnh cho một địa điểm. Mẫu yêu cầu chụp ảnh đã được đơn giản hoá. Giờ đây, bạn có thể yêu cầu PhotoMetadata trực tiếp từ đối tượng Place; bạn không cần phải gửi một yêu cầu riêng nữa. Ảnh có thể có chiều rộng hoặc chiều cao tối đa là 1600px. fetchPhoto() hoạt động tương tự như getPhoto().

Hãy làm theo các bước sau để tìm nạp ảnh địa điểm:

  1. Thiết lập cuộc gọi đến fetchPlace(). Hãy nhớ thêm trường PHOTO_METADATAS vào yêu cầu của bạn:

    List<Place.Field> fields = Arrays.asList(Place.Field.PHOTO_METADATAS);
    
  2. Lấy một đối tượng Địa điểm (ví dụ này sử dụng fetchPlace(), nhưng bạn cũng có thể sử dụng findCurrentPlace()):

    FetchPlaceRequest placeRequest = FetchPlaceRequest.builder(placeId, fields).build();
    
  3. Thêm OnSuccessListener để lấy siêu dữ liệu ảnh từ Place thu được trong FetchPlaceResponse, sau đó dùng siêu dữ liệu ảnh thu được để lấy một bitmap và văn bản ghi công:

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

Tìm một địa điểm từ vị trí của người dùng

Sử dụng findCurrentPlace() để tìm vị trí hiện tại của thiết bị mà người dùng đang sử dụng. findCurrentPlace()trả về một danh sách các PlaceLikelihood cho biết những địa điểm mà thiết bị của người dùng có khả năng ở đó nhất. findCurrentPlace() hoạt động tương tự như getCurrentPlace().

Hãy làm theo các bước sau để lấy vị trí hiện tại của thiết bị người dùng:

  1. Đảm bảo ứng dụng của bạn yêu cầu quyền ACCESS_FINE_LOCATIONACCESS_WIFI_STATE. Người dùng phải cấp quyền truy cập vào vị trí hiện tại của thiết bị. Hãy xem phần Yêu cầu quyền cho ứng dụng để biết thông tin chi tiết.

  2. Tạo một FindCurrentPlaceRequest, bao gồm danh sách các loại dữ liệu địa điểm cần trả về.

      // 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();
    
  3. Gọi findCurrentPlace và xử lý phản hồi, trước tiên hãy kiểm tra để xác minh rằng người dùng đã cấp quyền sử dụng vị trí của thiết bị.

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

Tìm cụm từ gợi ý của tính năng tự động hoàn thành

Sử dụng findAutocompletePredictions() để trả về các dự đoán về địa điểm để phản hồi các cụm từ tìm kiếm của người dùng. findAutocompletePredictions() hoạt động tương tự như getAutocompletePredictions().

Ví dụ sau đây minh hoạ cách gọi 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());
   }
});

Mã thông báo phiên

Mã thông báo phiên nhóm các giai đoạn truy vấn và lựa chọn của một lượt tìm kiếm của người dùng thành một phiên riêng biệt cho mục đích lập hoá đơn. Bạn nên sử dụng mã thông báo phiên cho tất cả các phiên tự động hoàn thành. Phiên bắt đầu khi người dùng bắt đầu nhập một cụm từ tìm kiếm và kết thúc khi họ chọn một địa điểm. Mỗi phiên có thể có nhiều cụm từ tìm kiếm, sau đó là một lựa chọn về địa điểm. Sau khi một phiên kết thúc, mã thông báo sẽ không còn hợp lệ nữa; ứng dụng của bạn phải tạo một mã thông báo mới cho mỗi phiên.

Mặt nạ trường

Trong các phương thức trả về thông tin chi tiết về địa điểm, bạn phải chỉ định những loại dữ liệu địa điểm cần trả về theo từng yêu cầu. Điều này giúp đảm bảo rằng bạn chỉ yêu cầu (và trả tiền cho) dữ liệu mà bạn sẽ thực sự sử dụng.

Để chỉ định loại dữ liệu cần trả về, hãy truyền một mảng Place.Field trong FetchPlaceRequest, như trong ví dụ sau:

// Include address, ID, and phone number.
List<Place.Field> placeFields = Arrays.asList(Place.Field.FORMATTED_ADDRESS,
                                              Place.Field.ID,
                                              Place.Field.INTERNATIONAL_PHONE_NUMBER);

Để xem danh sách các trường mà bạn có thể sử dụng trong mặt nạ trường, hãy xem phần Trường dữ liệu về địa điểm (Mới) .

Đọc thêm về SKU dữ liệu về địa điểm.

Bản cập nhật cho Place Picker và tính năng Autocomplete

Phần này giải thích những thay đổi đối với các tiện ích Places (Bộ chọn địa điểm và tính năng Tự động hoàn thành).

Tính năng tự động hoàn thành có lập trình

Sau đây là những thay đổi đối với tính năng tự động hoàn thành:

  • PlaceAutocomplete đổi tên thành Autocomplete.
    • PlaceAutocomplete.getPlace đổi tên thành Autocomplete.getPlaceFromIntent.
    • PlaceAutocomplete.getStatus đổi tên thành Autocomplete.getStatusFromIntent.
  • PlaceAutocomplete.RESULT_ERROR được đổi tên thành AutocompleteActivity.RESULT_ERROR (chế độ xử lý lỗi cho mảnh tự động hoàn thành KHÔNG thay đổi).

Bộ chọn địa điểm

Place Picker đã ngừng hoạt động từ ngày 29 tháng 1 năm 2019. Tính năng này đã bị tắt vào ngày 29 tháng 7 năm 2019 và không còn hoạt động nữa. Nếu tiếp tục sử dụng, bạn sẽ nhận được thông báo lỗi. SDK mới không hỗ trợ Trình chọn địa điểm.

Tiện ích tự động hoàn thành

Các tiện ích tự động hoàn thành đã được cập nhật:

  • Tiền tố Place đã bị xoá khỏi tất cả các lớp.
  • Thêm tính năng hỗ trợ cho mã thông báo phiên. Tiện ích này tự động quản lý mã thông báo cho bạn trong nền.
  • Đã thêm chế độ hỗ trợ cho mặt nạ trường, cho phép bạn chọn loại dữ liệu địa điểm cần trả về sau khi người dùng chọn.

Các phần sau đây hướng dẫn cách thêm một tiện ích tự động hoàn thành vào dự án của bạn.

Nhúng AutocompleteFragment

Để thêm một đoạn mã tự động hoàn thành, hãy làm theo các bước sau:

  1. Thêm một mảnh vào bố cục XML của hoạt động, như minh hoạ trong ví dụ sau.

    <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"
      />
    
  2. Để thêm tiện ích tự động hoàn thành vào hoạt động, hãy làm theo các bước sau:

    • Khởi chạy Places, truyền ngữ cảnh ứng dụng và khoá API của bạn.
    • Khởi động AutocompleteSupportFragment.
    • Gọi setPlaceFields() để cho biết các loại dữ liệu về địa điểm mà bạn muốn nhận.
    • Thêm một PlaceSelectionListener để làm việc gì đó với kết quả, cũng như xử lý mọi lỗi có thể xảy ra.

    Ví dụ sau đây minh hoạ cách thêm một tiện ích tự động hoàn thành vào một hoạt động:

    /**
     * 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);
        }
    });
    

Sử dụng một ý định để chạy hoạt động tự động hoàn thành

  1. Khởi chạy Places, truyền ngữ cảnh ứng dụng và khoá API của bạn
  2. Dùng Autocomplete.IntentBuilder để tạo một ý định, truyền chế độ PlaceAutocomplete mong muốn (toàn màn hình hoặc lớp phủ). Ý định phải gọi startActivityForResult, truyền vào một mã yêu cầu xác định ý định của bạn.
  3. Ghi đè lệnh gọi lại onActivityResult để nhận địa điểm đã chọn.

Ví dụ sau đây cho thấy cách sử dụng một ý định để khởi chạy tính năng tự động hoàn thành, sau đó xử lý kết quả:

    /**
     * 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.
            }
        }
    }

Công cụ chọn địa điểm không còn hoạt động nữa

Place Picker đã ngừng hoạt động từ ngày 29 tháng 1 năm 2019. Tính năng này đã bị tắt vào ngày 29 tháng 7 năm 2019 và không còn hoạt động nữa. Nếu tiếp tục sử dụng, bạn sẽ nhận được thông báo lỗi. SDK mới không hỗ trợ Trình chọn địa điểm.