Truy cập vào các API của Google bằng GoogleApiClient (không dùng nữa)

Bạn có thể sử dụng đối tượng GoogleApiClient ("Ứng dụng Google API") để truy cập vào các API của Google được cung cấp trong thư viện Dịch vụ Google Play (chẳng hạn như Đăng nhập bằng Google, Trò chơi và Drive). Ứng dụng API của Google cung cấp một điểm truy cập chung đến các dịch vụ của Google Play và quản lý kết nối mạng giữa thiết bị của người dùng và từng dịch vụ của Google.

Tuy nhiên, giao diện GoogleApi mới và các cách triển khai tương ứng sẽ dễ sử dụng hơn và là cách ưu tiên để truy cập vào các API của Dịch vụ Play. Hãy xem bài viết Truy cập API của Google.

Hướng dẫn này chỉ cho bạn cách:

  • Tự động quản lý kết nối của bạn với Dịch vụ Google Play.
  • Thực hiện các lệnh gọi API đồng bộ và không đồng bộ đến bất kỳ dịch vụ nào của Google Play.
  • Quản lý thủ công kết nối của bạn với Dịch vụ Google Play trong một số ít trường hợp cần thiết. Để tìm hiểu thêm, hãy xem bài viết Kết nối được quản lý theo cách thủ công.
Hình 1: Hình 1: Hình minh hoạ cách Ứng dụng API của Google cung cấp một giao diện để kết nối và thực hiện lệnh gọi đến bất kỳ dịch vụ nào của Google Play hiện có, chẳng hạn như Google Play Games và Google Drive.

Để bắt đầu, trước tiên, bạn phải cài đặt thư viện Dịch vụ Google Play (bản sửa đổi 15 trở lên) cho SDK Android. Làm theo hướng dẫn trong bài viết Thiết lập SDK Dịch vụ Google Play nếu bạn chưa thực hiện.

Bắt đầu mối kết nối được quản lý tự động

Sau khi dự án của bạn được liên kết với thư viện Dịch vụ Google Play, hãy tạo một thực thể của GoogleApiClient bằng cách sử dụng các API GoogleApiClient.Builder trong phương thức onCreate() của hoạt động. Lớp GoogleApiClient.Builder cung cấp các phương thức cho phép bạn chỉ định các API của Google mà bạn muốn sử dụng và các phạm vi OAuth 2.0 mà bạn muốn. Dưới đây là ví dụ về mã sẽ tạo một thực thể GoogleApiClient kết nối với dịch vụ Google Drive:

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
    .enableAutoManage(this /* FragmentActivity */,
                      this /* OnConnectionFailedListener */)
    .addApi(Drive.API)
    .addScope(Drive.SCOPE_FILE)
    .build();

Bạn có thể thêm nhiều API và nhiều phạm vi vào cùng một GoogleApiClient bằng cách thêm các lệnh gọi bổ sung vào addApi()addScope().

Lưu ý quan trọng: Nếu thêm API Wearable cùng với các API khác vào GoogleApiClient, bạn có thể gặp lỗi kết nối với ứng dụng trên các thiết bị chưa cài đặt ứng dụng Wear OS. Để tránh lỗi kết nối, hãy gọi phương thức addApiIfAvailable() và chuyển vào API Wearable để cho phép ứng dụng của bạn xử lý linh hoạt API bị thiếu. Để biết thêm thông tin, hãy xem bài viết Truy cập vào Wearable API (API cho thiết bị đeo).

Để bắt đầu một kết nối được quản lý tự động, bạn phải chỉ định phương thức triển khai cho giao diện OnConnectionFailedListener để nhận các lỗi kết nối không thể giải quyết. Khi thực thể GoogleApiClient được quản lý tự động của bạn cố gắng kết nối với các API của Google, thực thể đó sẽ tự động hiển thị giao diện người dùng để cố gắng khắc phục mọi lỗi kết nối có thể giải quyết (ví dụ: nếu cần cập nhật Dịch vụ Google Play). Nếu xảy ra lỗi không thể giải quyết, bạn sẽ nhận được lệnh gọi đến onConnectionFailed().

Bạn cũng có thể chỉ định phương thức triển khai không bắt buộc cho giao diện ConnectionCallbacks nếu ứng dụng của bạn cần biết thời điểm thiết lập hoặc tạm ngưng kết nối được quản lý tự động. Ví dụ: nếu ứng dụng của bạn thực hiện các lệnh gọi để ghi dữ liệu vào các API của Google, thì các lệnh gọi này chỉ được gọi sau khi phương thức onConnected() được gọi.

Dưới đây là một hoạt động mẫu triển khai giao diện gọi lại và thêm các giao diện đó vào Ứng dụng API của Google:

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import gms.drive.*;
import android.support.v4.app.FragmentActivity;

public class MyActivity extends FragmentActivity
        implements OnConnectionFailedListener {
    private GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a GoogleApiClient instance
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this /* FragmentActivity */,
                                  this /* OnConnectionFailedListener */)
                .addApi(Drive.API)
                .addScope(Drive.SCOPE_FILE)
                .build();

        // ...
    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        // An unresolvable error has occurred and a connection to Google APIs
        // could not be established. Display an error message, or handle
        // the failure silently

        // ...
    }
}

Thực thể GoogleApiClient của bạn sẽ tự động kết nối sau khi hoạt động gọi onStart() và ngắt kết nối sau khi gọi onStop(). Ứng dụng của bạn có thể bắt đầu ngay lập tức gửi yêu cầu đọc đến các API của Google sau khi tạo GoogleApiClient mà không cần đợi kết nối hoàn tất.

Kết nối với các dịch vụ của Google

Sau khi kết nối, ứng dụng của bạn có thể thực hiện các lệnh gọi đọc và ghi bằng các API dành riêng cho dịch vụ mà ứng dụng của bạn được uỷ quyền, như được chỉ định bởi các API và phạm vi mà bạn đã thêm vào thực thể GoogleApiClient.

Lưu ý: Trước khi thực hiện lệnh gọi đến các dịch vụ cụ thể của Google, trước tiên, bạn có thể cần đăng ký ứng dụng của mình trong Google Developer Console. Để biết hướng dẫn, hãy tham khảo hướng dẫn bắt đầu sử dụng thích hợp cho API mà bạn đang sử dụng, chẳng hạn như Google Drive hoặc Đăng nhập bằng Google.

Khi bạn thực hiện yêu cầu đọc hoặc ghi bằng GoogleApiClient, ứng dụng API sẽ trả về đối tượng PendingResult đại diện cho yêu cầu đó. Việc này xảy ra ngay lập tức trước khi yêu cầu được gửi đến dịch vụ của Google mà ứng dụng của bạn đang gọi.

Ví dụ: sau đây là yêu cầu đọc tệp từ Google Drive cung cấp đối tượng PendingResult:

Query query = new Query.Builder()
        .addFilter(Filters.eq(SearchableField.TITLE, filename));
PendingResult<DriveApi.MetadataBufferResult> result = Drive.DriveApi.query(mGoogleApiClient, query);

Sau khi ứng dụng của bạn có đối tượng PendingResult, ứng dụng có thể chỉ định xem yêu cầu được xử lý dưới dạng lệnh gọi không đồng bộ hay là lệnh gọi đồng bộ.

Lưu ý: Ứng dụng của bạn có thể thêm các yêu cầu đọc vào hàng đợi khi không kết nối với Dịch vụ Google Play. Ví dụ: ứng dụng của bạn có thể gọi các phương thức để đọc tệp từ Google Drive, bất kể thực thể GoogleApiClient của bạn đã được kết nối hay chưa. Sau khi thiết lập kết nối, các yêu cầu đọc được thêm vào hàng đợi sẽ được thực thi. Các yêu cầu ghi sẽ gặp lỗi nếu ứng dụng của bạn gọi phương thức ghi của Dịch vụ Google Play trong khi Ứng dụng Google API chưa được kết nối.

Sử dụng lệnh gọi không đồng bộ

Để thực hiện yêu cầu không đồng bộ, hãy gọi setResultCallback() trên PendingResult và triển khai giao diện ResultCallback. Ví dụ: sau đây là yêu cầu được thực thi không đồng bộ:

private void loadFile(String filename) {
    // Create a query for a specific filename in Drive.
    Query query = new Query.Builder()
            .addFilter(Filters.eq(SearchableField.TITLE, filename))
            .build();
    // Invoke the query asynchronously with a callback method
    Drive.DriveApi.query(mGoogleApiClient, query)
            .setResultCallback(new ResultCallback<DriveApi.MetadataBufferResult>() {
        @Override
        public void onResult(DriveApi.MetadataBufferResult result) {
            // Success! Handle the query result.
            // ...
        }
    });
}

Khi ứng dụng của bạn nhận được một đối tượng Result trong lệnh gọi lại onResult(), ứng dụng đó sẽ được phân phối dưới dạng một thực thể của lớp con thích hợp theo chỉ định của API bạn đang sử dụng, chẳng hạn như DriveApi.MetadataBufferResult.

Sử dụng lệnh gọi đồng bộ

Nếu muốn mã thực thi theo thứ tự được xác định nghiêm ngặt, có thể là do kết quả của một lệnh gọi là đối số cho lệnh gọi khác, bạn có thể thực hiện yêu cầu đồng bộ bằng cách gọi await() trên PendingResult. Thao tác này sẽ chặn luồng và trả về đối tượng Result khi yêu cầu hoàn tất. Đối tượng này được phân phối dưới dạng một thực thể của lớp con thích hợp theo chỉ định của API mà bạn đang sử dụng, ví dụ như DriveApi.MetadataBufferResult.

Vì việc gọi await() sẽ chặn luồng cho đến khi có kết quả, nên ứng dụng của bạn tuyệt đối không được gửi yêu cầu đồng bộ đến các API của Google trên luồng giao diện người dùng. Ứng dụng của bạn có thể tạo một luồng mới bằng cách sử dụng đối tượng AsyncTask và sử dụng luồng đó để tạo yêu cầu đồng bộ.

Ví dụ sau đây minh hoạ cách gửi một yêu cầu tệp đến Google Drive dưới dạng lệnh gọi đồng bộ:

private void loadFile(String filename) {
    new GetFileTask().execute(filename);
}

private class GetFileTask extends AsyncTask {
    protected void doInBackground(String filename) {
        Query query = new Query.Builder()
                .addFilter(Filters.eq(SearchableField.TITLE, filename))
                .build();
        // Invoke the query synchronously
        DriveApi.MetadataBufferResult result =
                Drive.DriveApi.query(mGoogleApiClient, query).await();

        // Continue doing other stuff synchronously
        // ...
    }
}

Truy cập vào Wearable API (API cho thiết bị đeo)

API thiết bị đeo cung cấp một kênh liên lạc cho các ứng dụng chạy trên thiết bị cầm tay và thiết bị đeo. API này bao gồm một tập hợp các đối tượng dữ liệu mà hệ thống có thể gửi và đồng bộ hoá, cũng như các trình nghe thông báo cho ứng dụng của bạn về các sự kiện quan trọng thông qua một lớp dữ liệu. API cho thiết bị đeo có trên các thiết bị chạy Android 4.3 (API cấp 18) trở lên khi thiết bị đeo được kết nối và cài đặt ứng dụng đồng hành Wear OS trên thiết bị.

Sử dụng độc lập API Wearable

Nếu ứng dụng của bạn dùng API cho thiết bị đeo nhưng không dùng các API khác của Google, thì bạn có thể thêm API này bằng cách gọi phương thức addApi(). Ví dụ sau cho biết cách thêm API cho thiết bị đeo vào thực thể GoogleApiClient:

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
    .enableAutoManage(this /* FragmentActivity */,
                      this /* OnConnectionFailedListener */)
    .addApi(Wearable.API)
    .build();

Trong trường hợp không có API cho thiết bị đeo, các yêu cầu kết nối có chứa API cho thiết bị đeo sẽ không thực hiện được kèm theo mã lỗi API_UNAVAILABLE.

Ví dụ sau đây minh hoạ cách xác định xem có Wearable API hay không:

// Connection failed listener method for a client that only
// requests access to the Wearable API
@Override
public void onConnectionFailed(ConnectionResult result) {
    if (result.getErrorCode() == ConnectionResult.API_UNAVAILABLE) {
        // The Wearable API is unavailable
    }
    // ...
}

Sử dụng API cho thiết bị đeo với các API khác của Google

Nếu ứng dụng của bạn dùng API cho thiết bị đeo ngoài các API khác của Google, hãy gọi phương thức addApiIfAvailable() và truyền API cho thiết bị đeo để kiểm tra xem ứng dụng đó có sẵn hay không. Bạn có thể sử dụng bước kiểm tra này để giúp ứng dụng xử lý linh hoạt các trường hợp không có API.

Ví dụ sau cho biết cách truy cập vào API cho thiết bị đeo cùng với API Drive:

// Create a GoogleApiClient instance
mGoogleApiClient = new GoogleApiClient.Builder(this)
        .enableAutoManage(this /* FragmentActivity */,
                          this /* OnConnectionFailedListener */)
        .addApi(Drive.API)
        .addApiIfAvailable(Wearable.API)
        .addScope(Drive.SCOPE_FILE)
        .build();

Trong ví dụ trên, GoogleApiClient có thể kết nối thành công với Google Drive mà không cần kết nối với API cho thiết bị đeo nếu không có sẵn. Sau khi bạn kết nối thực thể GoogleApiClient, hãy đảm bảo rằng API cho thiết bị đeo đã sẵn sàng trước khi thực hiện lệnh gọi API:

boolean wearAvailable = mGoogleApiClient.hasConnectedApi(Wearable.API);

Bỏ qua lỗi kết nối API

Nếu bạn gọi addApi()GoogleApiClient không thể kết nối thành công với API đó, thì toàn bộ thao tác kết nối cho ứng dụng đó sẽ không thành công và kích hoạt lệnh gọi lại onConnectionFailed().

Bạn có thể đăng ký lỗi kết nối API sẽ bị bỏ qua bằng cách sử dụng addApiIfAvailable(). Nếu một API được thêm bằng addApiIfAvailable() không kết nối được do lỗi không thể khôi phục (chẳng hạn như API_UNAVAILABLE đối với Wear), thì API đó sẽ bị loại bỏ khỏi GoogleApiClient và ứng dụng sẽ tiếp tục kết nối với các API khác. Tuy nhiên, nếu không kết nối được với API kèm theo lỗi có thể khôi phục (chẳng hạn như ý định giải quyết sự đồng ý bằng OAuth), thì thao tác kết nối ứng dụng sẽ không thành công. Khi sử dụng kết nối được quản lý tự động, GoogleApiClient sẽ cố gắng giải quyết các lỗi như vậy khi có thể. Khi bạn sử dụng kết nối được quản lý thủ công, một ConnectionResult chứa ý định giải quyết sẽ được gửi đến lệnh gọi lại onConnectionFailed(). Lỗi kết nối API sẽ chỉ bị bỏ qua nếu không có giải pháp cho lỗi này và API đã được thêm bằng addApiIfAvailable(). Để tìm hiểu cách triển khai phương thức xử lý lỗi kết nối theo cách thủ công, hãy xem bài viết Xử lý lỗi kết nối.

Vì các API được thêm bằng addApiIfAvailable() có thể không phải lúc nào cũng hiện diện trong thực thể GoogleApiClient đã kết nối, bạn nên bảo vệ các lệnh gọi đến những API này bằng cách thêm một dấu kiểm thông qua hasConnectedApi(). Để tìm hiểu lý do tại sao một API cụ thể không kết nối được khi toàn bộ thao tác kết nối thành công đối với ứng dụng, hãy gọi getConnectionResult() và lấy mã lỗi từ đối tượng ConnectionResult. Nếu ứng dụng của bạn gọi một API khi chưa kết nối với ứng dụng đó, thì lệnh gọi sẽ không thực hiện được mã trạng thái API_NOT_AVAILABLE.

Nếu API mà bạn đang thêm thông qua addApiIfAvailable() yêu cầu một hoặc nhiều phạm vi, hãy thêm các phạm vi đó làm tham số trong lệnh gọi phương thức addApiIfAvailable() thay vì sử dụng phương thức addScope(). Các phạm vi được thêm bằng phương pháp này có thể không được yêu cầu nếu kết nối API không thành công trước khi nhận được sự đồng ý của OAuth, trong khi các phạm vi được thêm bằng addScope() luôn được yêu cầu.

Các kết nối được quản lý thủ công

Phần lớn trong hướng dẫn này cho bạn biết cách sử dụng phương thức enableAutoManage để bắt đầu một kết nối được quản lý tự động thông qua các lỗi được tự động giải quyết. Trong hầu hết trường hợp, đây là cách tốt nhất và dễ nhất để kết nối với các API của Google từ ứng dụng Android của bạn. Tuy nhiên, có một số trường hợp mà bạn muốn sử dụng kết nối được quản lý theo cách thủ công đến các API của Google trong ứng dụng của mình:

  • Để truy cập vào các API của Google bên ngoài một hoạt động hoặc duy trì quyền kiểm soát kết nối API
  • Để tuỳ chỉnh cách xử lý và giải quyết lỗi kết nối

Phần này đưa ra ví dụ về những cách này và các trường hợp sử dụng nâng cao khác.

Bắt đầu kết nối được quản lý theo cách thủ công

Để bắt đầu một kết nối được quản lý theo cách thủ công tới GoogleApiClient, bạn phải chỉ định phương thức triển khai cho giao diện gọi lại, ConnectionCallbacksOnConnectionFailedListener. Các giao diện này nhận được lệnh gọi lại để phản hồi phương thức connect() không đồng bộ khi kết nối với Dịch vụ Google Play thành công, không thành công hoặc bị tạm ngưng.

    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Drive.API)
            .addScope(Drive.SCOPE_FILE)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build()

Khi quản lý kết nối theo cách thủ công, bạn sẽ cần gọi phương thức connect()disconnect() tại các điểm thích hợp trong vòng đời của ứng dụng. Trong ngữ cảnh hoạt động, phương pháp hay nhất là gọi connect() trong phương thức onStart() của hoạt động và disconnect() trong phương thức onStop() của hoạt động. Phương thức connect()disconnect() được gọi tự động khi sử dụng kết nối được quản lý tự động.

Nếu bạn đang sử dụng GoogleApiClient để kết nối với các API yêu cầu xác thực, chẳng hạn như Google Drive hoặc Google Play Games, thì có khả năng lần kết nối đầu tiên của bạn sẽ không thành công và ứng dụng của bạn sẽ nhận được lệnh gọi đến onConnectionFailed() kèm theo lỗi SIGN_IN_REQUIRED vì tài khoản người dùng chưa được chỉ định.

Xử lý lỗi kết nối

Khi ứng dụng nhận được một lệnh gọi đến lệnh gọi lại onConnectionFailed(), bạn nên gọi hasResolution() trên đối tượng ConnectionResult đã cung cấp. Nếu giá trị này trả về giá trị true (đúng), ứng dụng của bạn có thể yêu cầu người dùng thực hiện hành động ngay lập tức để khắc phục lỗi bằng cách gọi startResolutionForResult() trên đối tượng ConnectionResult. Phương thức startResolutionForResult() sẽ hoạt động giống như startActivityForResult() trong trường hợp này và khởi chạy một hoạt động phù hợp với bối cảnh giúp người dùng giải quyết lỗi (chẳng hạn như một hoạt động giúp người dùng chọn một tài khoản).

Nếu hasResolution() trả về giá trị false, ứng dụng của bạn sẽ gọi GoogleApiAvailability.getErrorDialog() và truyền mã lỗi vào phương thức này. Thao tác này sẽ trả về một Dialog do Dịch vụ Google Play cung cấp phù hợp với lỗi. Hộp thoại có thể chỉ đưa ra thông báo giải thích lỗi, hoặc cũng có thể đưa ra một thao tác để khởi chạy một hoạt động có thể khắc phục lỗi (chẳng hạn như khi người dùng cần cài đặt một phiên bản mới hơn của Dịch vụ Google Play).

Ví dụ: giờ đây phương thức gọi lại onConnectionFailed() của bạn sẽ có dạng như sau:

public class MyActivity extends Activity
        implements ConnectionCallbacks, OnConnectionFailedListener {

    // Request code to use when launching the resolution activity
    private static final int REQUEST_RESOLVE_ERROR = 1001;
    // Unique tag for the error dialog fragment
    private static final String DIALOG_ERROR = "dialog_error";
    // Bool to track whether the app is already resolving an error
    private boolean mResolvingError = false;

    // ...

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        if (mResolvingError) {
            // Already attempting to resolve an error.
            return;
        } else if (result.hasResolution()) {
            try {
                mResolvingError = true;
                result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
            } catch (SendIntentException e) {
                // There was an error with the resolution intent. Try again.
                mGoogleApiClient.connect();
            }
        } else {
            // Show dialog using GoogleApiAvailability.getErrorDialog()
            showErrorDialog(result.getErrorCode());
            mResolvingError = true;
        }
    }

    // The rest of this code is all about building the error dialog

    /* Creates a dialog for an error message */
    private void showErrorDialog(int errorCode) {
        // Create a fragment for the error dialog
        ErrorDialogFragment dialogFragment = new ErrorDialogFragment();
        // Pass the error that should be displayed
        Bundle args = new Bundle();
        args.putInt(DIALOG_ERROR, errorCode);
        dialogFragment.setArguments(args);
        dialogFragment.show(getSupportFragmentManager(), "errordialog");
    }

    /* Called from ErrorDialogFragment when the dialog is dismissed. */
    public void onDialogDismissed() {
        mResolvingError = false;
    }

    /* A fragment to display an error dialog */
    public static class ErrorDialogFragment extends DialogFragment {
        public ErrorDialogFragment() { }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            // Get the error code and retrieve the appropriate dialog
            int errorCode = this.getArguments().getInt(DIALOG_ERROR);
            return GoogleApiAvailability.getInstance().getErrorDialog(
                    this.getActivity(), errorCode, REQUEST_RESOLVE_ERROR);
        }

        @Override
        public void onDismiss(DialogInterface dialog) {
            ((MyActivity) getActivity()).onDialogDismissed();
        }
    }
}

Sau khi người dùng hoàn tất hộp thoại do startResolutionForResult() cung cấp hoặc đóng thông báo do GoogleApiAvailability.getErrorDialog() cung cấp, hoạt động của bạn sẽ nhận được lệnh gọi lại onActivityResult() cùng với mã kết quả RESULT_OK. Sau đó, ứng dụng của bạn có thể gọi lại connect(). Ví dụ:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_RESOLVE_ERROR) {
        mResolvingError = false;
        if (resultCode == RESULT_OK) {
            // Make sure the app is not already connected or attempting to connect
            if (!mGoogleApiClient.isConnecting() &&
                    !mGoogleApiClient.isConnected()) {
                mGoogleApiClient.connect();
            }
        }
    }
}

Trong mã trên, bạn có thể nhận thấy giá trị boolean mResolvingError. Tính năng này theo dõi trạng thái ứng dụng trong khi người dùng đang giải quyết lỗi để tránh lặp lại các lần khắc phục cùng một lỗi. Ví dụ: mặc dù hộp thoại bộ chọn tài khoản đang hiển thị để giúp người dùng khắc phục lỗi SIGN_IN_REQUIRED, nhưng người dùng có thể xoay màn hình. Việc này sẽ tạo lại hoạt động và khiến phương thức onStart() được gọi lại, sau đó gọi lại connect(). Điều này dẫn đến một lệnh gọi khác đến startResolutionForResult(), để tạo một hộp thoại bộ chọn tài khoản khác phía trước hộp thoại hiện có.

Giá trị boolean này chỉ phục vụ mục đích nếu vẫn tồn tại trên các thực thể hoạt động. Phần tiếp theo giải thích cách duy trì trạng thái xử lý lỗi của ứng dụng bất kể các thao tác hoặc sự kiện khác của người dùng xảy ra trên thiết bị.

Duy trì trạng thái trong khi giải quyết lỗi

Để tránh thực thi mã trong onConnectionFailed() khi đang cố gắng khắc phục lỗi trước đó, bạn cần giữ lại boolean theo dõi xem ứng dụng của bạn đã cố gắng khắc phục lỗi hay chưa.

Như minh hoạ trong ví dụ về mã ở trên, ứng dụng của bạn phải đặt boolean thành true mỗi khi gọi startResolutionForResult() hoặc hiển thị hộp thoại từ GoogleApiAvailability.getErrorDialog(). Sau đó, khi ứng dụng của bạn nhận được RESULT_OK trong lệnh gọi lại onActivityResult(), hãy đặt boolean thành false.

Để theo dõi boolean khi hoạt động khởi động lại (chẳng hạn như khi người dùng xoay màn hình), hãy lưu boolean vào dữ liệu thực thể đã lưu của hoạt động bằng cách sử dụng onSaveInstanceState():

private static final String STATE_RESOLVING_ERROR = "resolving_error";

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBoolean(STATE_RESOLVING_ERROR, mResolvingError);
}

Sau đó, hãy khôi phục trạng thái đã lưu trong onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // ...
    mResolvingError = savedInstanceState != null
            && savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false);
}

Bây giờ, bạn có thể chạy ứng dụng và kết nối với Dịch vụ Google Play theo cách thủ công một cách an toàn.