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

Hướng dẫn này giải thích những thay đổi giữa thư viện khả năng tương thích của Google Địa điểm và phiên bản độc lập mới của SDK địa điểm dành cho Android. Nếu bạn đã sử dụng thư viện khả năng tương thích của Địa điểm thay vì di chuyển sang phiên bản độc lập mới của SDK Địa điểm dành cho Android, thì hướng dẫn này sẽ chỉ cho bạn cách cập nhật các dự án để sử dụng phiên bản mới của SDK Địa điểm dành 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 SDK địa điểm dành cho Android phiên bản 2.6.0 trở lên là sử dụng SDK địa điểm dành cho Android. Bạn nên cập nhật thư viện tương thích lên SDK Địa điểm mới cho phiên bản Android càng sớm càng tốt.

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

Các vùng thay đổi chính như sau:

  • Phiên bản mới của SDK Địa điểm dành cho Android được phân phối dưới dạng thư viện ứng dụng tĩnh. Trước tháng 1 năm 2019, SDK Địa điểm dành cho Android được cung cấp thông qua Dịch vụ Google Play. Kể từ đó, thư viện khả năng tương thích của Địa điểm đã được cung cấp để dễ dàng chuyển đổi sang SDK Địa điểm mới cho Android.
  • các phương pháp hoàn toàn mới.
  • Chúng tôi hiện hỗ trợ mặt nạ trường 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 loại dữ liệu địa điểm cần trả về.
  • Chúng tôi đã cải thiện các 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.
  • Bộ chọn địa điểm không còn hoạt động nữa.

Giới thiệu về thư viện khả năng tương thích với Google Địa điểm

Vào tháng 1 năm 2019, với việc phát hành Phiên bản 1.0 của SDK Địa điểm độc lập cho Android, Google đã cung cấp một thư viện tương thích để giúp di chuyển từ phiên bản Dịch vụ Google Play đã ngừng hoạt động của SDK Địa điểm dành cho Android (com.google.android.gms:play-services-places).

Thư viện tương thích này tạm thời được cung cấp để chuyển hướng và dịch các lệnh gọi API dành cho phiên bản Dịch vụ Google Play sang phiên bản độc lập mới cho đến khi các nhà phát triển có thể di chuyển mã của mình để sử dụng tên mới trong SDK độc lập. Đối với mỗi phiên bản SDK Địa điểm dành cho 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 khả năng tương thích Địa điểm đã đượ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 khả năng tương thích của Google Địa điểm

Tất cả phiên bản của thư viện khả năng tương thích cho SDK Địa điểm dành cho 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 cuối cùng của thư viện tương thích Google Địa điểm. Cách duy nhất để truy cập vào các tính năng và bản sửa lỗi trong SDK Địa điểm dành cho Android phiên bản 2.6.0 trở lên là sử dụng SDK Địa điểm dành cho Android.

Bạn nên di chuyển sang SDK Địa điểm dành cho Android để truy cập vào 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 dưới đây trong phần Cài đặt SDK địa điểm dành cho Android để di chuyển sang SDK Địa điểm dành cho Android.

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

Phiên bản mới của SDK Địa điểm dành cho Android được phân phối dưới dạng thư viện ứng dụng tĩnh.

Sử dụng Maven để thêm SDK Địa điểm dành cho Android vào dự án Android Studio của bạn:

  1. Nếu bạn đang sử dụng thư viện khả năng tương thích của Google Địa điểm:

    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 để chuyển sang SDK Địa điểm dành cho Android:

          implementation 'com.google.android.libraries.places:places:2.7.0'

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

    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 để chuyển sang SDK Địa điểm dành cho Android:

          implementation 'com.google.android.libraries.places:places:2.7.0'

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

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

  5. Cập nhật thành phần "Do Google cung cấp":

    @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 bản dựng nào do việc chuyển đổi sang SDK Địa điểm dành cho Android, hãy xem các phần dưới đây để biết thông tin về cách giải quyết các lỗi này.

Khởi chạy ứng dụng SDK Địa điểm mới

Khởi động ứng dụng SDK Địa điểm 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. Lỗi giới hạn QPS hiện được trả về thông qua PlaceStatusCodes.OVER_QUERY_LIMIT. Không còn giới hạn về QPD.

Các mã trạng thái sau đây đã được thêm:

  • 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 nào.
    • Bạn đã cung cấp một khóa API không hợp lệ.
    • API Địa điểm chưa được bật trong Bảng điều khiển đám mây.
    • Khoá API đã được cung cấp kèm theo các quy tắc hạn chế khoá không chính xác.
  • INVALID_REQUEST – Yêu cầu không hợp lệ do đối số bị thiếu hoặc 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 SDK Địa điểm dành cho 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:

  • Điểm cuối không còn sử dụng động từ get.
  • 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 ứng dụng tương ứng.
  • Các đối tượng yêu cầu hiện có các trình tạo; các thông số bắt buộc được chuyển dưới dạng thông số trình tạo yêu cầu.
  • Các vùng đệm không còn được sử dụng nữa.

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

Tìm nạp địa điểm theo mã

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ư hàm getPlaceById().

Làm theo các bước sau để tìm nạp địa điểm:

  1. Gọi fetchPlace(), chuyển đối tượng FetchPlaceRequest chỉ định 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.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. Trả về một kết quả 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());
        }
    });
    

Tìm nạp ảnh địa điểm

Sử dụng fetchPhoto() để tải ảnh địa điểm. fetchPhoto() trả lại ảnh về một địa điểm. Mẫu đơn giản để yêu cầu ảnh đã được đơn giản hoá. Bây giờ, bạn có thể yêu cầu PhotoMetadata trực tiếp từ đối tượng Place; một yêu cầu riêng không còn cần thiết 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 tới 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 đố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 đó sử dụng siêu dữ liệu ảnh thu được để lấy 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ại 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ị. findCurrentPlace() trả về danh sách PlaceLikelihood cho biết những nơi có nhiều khả năng đặt thiết bị của người dùng nhất. findCurrentPlace() có chức năng tương tự như getCurrentPlace().

Làm theo các bước sau để lấy thông tin vị trí hiện tại của thiết bị mà người dùng đang sử dụng:

  1. Hãy đả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 thông tin vị trí hiện tại của thiết bị. Hãy xem bài viết Yêu cầu quyền cho ứng dụng để biết thông tin chi tiết.

  2. Tạo 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.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, kiểm tra trước để xác minh rằng người dùng đã cấp quyền sử dụng vị trí 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ụm từ gợi ý địa điểm để phản hồi cụm từ tìm kiếm của người dùng. findAutocompletePredictions() có chức năng tương tự như getAutocompletePredictions().

Ví dụ sau cho thấy 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 sẽ nhóm các giai đoạn truy vấn và 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 thanh toán. Bạn nên sử dụng mã thông báo phiên cho mọi phiên tự động hoàn thành. Phiên hoạt động bắt đầu khi người dùng bắt đầu nhập một truy vấn và kết thúc khi họ chọn một địa điểm. Mỗi phiên có thể có nhiều truy vấn, theo sau là một lựa chọn đị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ệ; ứ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 hoạt động.

Khẩu trang

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 loại dữ liệu địa điểm cần trả về cho mỗi yêu cầu. Điều này giúp đảm bảo rằng bạn chỉ yêu cầu (và thanh toán) 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 chuyể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.ADDRESS,
                                              Place.Field.ID,
                                              Place.Field.PHONE_NUMBER);

Bạn có thể sử dụng một hoặc nhiều trường sau:

  • Place.Field.ADDRESS
  • Place.Field.ID
  • Place.Field.LAT_LNG
  • Place.Field.NAME
  • Place.Field.OPENING_HOURS
  • Place.Field.PHONE_NUMBER
  • Place.Field.PHOTO_METADATAS
  • Place.Field.PLUS_CODE
  • Place.Field.PRICE_LEVEL
  • Place.Field.RATING
  • Place.Field.TYPES
  • Place.Field.USER_RATINGS_TOTAL
  • Place.Field.VIEWPORT
  • Place.Field.WEBSITE_URI

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

Thông tin cập nhật về Bộ chọn địa điểm và Tự động hoàn thành

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

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

Các thay đổi sau đây đã được thực hiện để 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 (lỗi xử lý tự động hoàn thành chưa được thay đổi).

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

Bộ chọn địa điểm đã ngừng hoạt động vào ngày 29 tháng 1 năm 2019. Dịch vụ 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. Việc tiếp tục sử dụng sẽ dẫn đến thông báo lỗi. SDK mới không hỗ trợ Bộ chọn địa điểm.

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

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

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

Các phần sau đây cho biết cách thêm tiện ích tự động hoàn thành vào dự án.

Nhúng AutocompleteFragment

Để thêm một mảnh 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 thực hiện các bước sau:

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

    Ví dụ sau đây cho thấy việc thêm 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.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);
        }
    });
    

Dùng một ý định để chạy hoạt động tự động hoàn thành

  1. Khởi chạy Places, chuyển ngữ cảnh của ứng dụng và khoá API
  2. Sử dụng Autocomplete.IntentBuilder để tạo ý định, chuyể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 bạn biết cách sử dụng ý định để chạy tính năng tự động hoàn thành và 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.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.
            }
        }
    }

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

Bộ chọn địa điểm đã ngừng hoạt động vào ngày 29 tháng 1 năm 2019. Dịch vụ 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. Việc tiếp tục sử dụng sẽ dẫn đến thông báo lỗi. SDK mới không hỗ trợ Bộ chọn địa điểm.