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

Bạn có thể dùng GoogleApiClient ("Ứng dụng API của Google") đối tượng để 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 Google API cung cấp điểm truy cập chung đến các dịch vụ của Google Play và quản lý mạng kết nối 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 hơn cùng các cách triển khai sẽ dễ dàng hơn và là cách ưu tiên để truy cập vào 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 những trường hợp hiếm gặp nếu cần. Để 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 minh hoạ cách Ứng dụng Google API cung cấp để kết nối và gọi điện đến bất kỳ dịch vụ Google Play nào 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 của bạn. Nếu bạn chưa làm như vậy, hãy làm theo hướng dẫn trong Thiết lập SDK Dịch vụ Google Play.

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 phiên bản của GoogleApiClient bằng cách sử dụng GoogleApiClient.Builder API trong hoạt động của bạn onCreate() . Chiến lược phát hành đĩa đơn 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 cũng như Phạm vi OAuth 2.0. Dưới đây là ví dụ về mã sẽ tạo một Phiên bản 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 nơi GoogleApiClient bằng cách thêm các lệnh gọi khác vào addApi()addScope().

Lưu ý quan trọng: Nếu bạn thêm API Wearable cùng với các API khác vào một GoogleApiClient, bạn có thể gặp lỗi kết nối với ứng dụng trên những thiết bị chưa cài đặt ứng dụng Wear OS. Người nhận tránh lỗi kết nối, hãy gọi phương thức addApiIfAvailable() rồi chuyển vào Wearable API để cho phép ứng dụng của bạn xử lý linh hoạt phần dữ liệu bị thiếu API. Để 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 cho OnConnectionFailedListener nhận được lỗi kết nối không thể giải quyết được. Khi chế độ cài đặt được quản lý tự động Thực thể GoogleApiClient cố gắng kết nối với các API của Google, thực thể này sẽ tự động giao diện người dùng hiển thị để 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 Người dùng cần cập nhật Dịch vụ Google Play). Nếu xảy ra lỗi mà không thể đã giải quyết, bạn sẽ nhận được cuộc 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 kết nối được quản lý tự động được thiết lập hoặc bị tạm ngưng. Ví dụ: nếu ứng dụng của bạn thực hiện 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 sẽ được gọi chỉ sau khi gọi phương thức onConnected().

Dưới đây là một hoạt động mẫu triển khai giao diện gọi lại và thêm chúng đến Ứng dụng Google API:

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 sẽ tự động kết nối sau hoạt động của bạn 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 đọc các yêu cầu tới API của Google sau khi tạo GoogleApiClient mà không đang chờ 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, khách hàng của bạn có thể thực hiện lệnh gọi đọc và ghi bằng API dành riêng cho dịch vụ cho mà ứng dụng của bạn được cho phép, 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 gọi đến các dịch vụ cụ thể của Google, trước tiên, bạn có thể cần phải đăng ký trong Google Developer Console. Để được hướng dẫn, hãy tham khảo hướng dẫn bắt đầu cho API 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ụ: đâ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ó một đối tượng PendingResult, sau đó ứng dụng của bạn 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ệ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. Cho 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. Việc ghi yêu cầu sẽ gây ra lỗi nếu ứng dụng của bạn gọi Các phương thức ghi của Dịch vụ Google Play khi Ứng dụng Google API của bạn chưa được kết nối.

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

Để làm cho yêu cầu không đồng bộ, hãy gọi setResultCallback() trên PendingResult và cung cấp việc triển khai Giao diện ResultCallback. Cho 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(), lớp 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, chẳng hạn như DriveApi.MetadataBufferResult.

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

Nếu bạn muốn mã thực thi theo một thứ tự được xác định nghiêm ngặt, có thể là do kết quả của một cần thiết làm đối số cho một lệnh gọi khác, bạn có thể làm cho yêu cầu của mình đồ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 như được chỉ định bởi API mà bạn đang sử dụng, ví dụ: DriveApi.MetadataBufferResult.

Vì gọi await() chặn luồng cho đến khi có kết quả, ứng dụng của bạn không được thực hiện 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á, và trình nghe thông báo cho ứng dụng của bạn về các sự kiện quan trọng bằng cách sử dụng lớp dữ liệu. Chiến lược phát hành đĩa đơn API cho thiết bị đeo có trên những thiết bị chạy Android 4.3 (API cấp 18) trở lên khi một thiết bị đeo đã kết nối và ứng dụng đồng hành Wear OS đã được cài đặt trên thiết bị.

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

Nếu ứng dụng của bạn sử dụng API cho thiết bị đeo nhưng không sử 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 đến 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, những yêu cầu kết nối bao gồm API cho thiết bị đeo không thành công với API_UNAVAILABLE mã lỗi.

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 sử dụng API cho thiết bị đeo ngoài các API khác của Google, hãy gọi hàm addApiIfAvailable() và truyền API cho thiết bị đeo để kiểm tra xem API đó 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 thấy cách truy cập vào Wearable API 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 không kết nối với API cho thiết bị đeo nếu không có sẵn. Sau bạn kết nối GoogleApiClient của mình chẳng hạn như đảm bảo rằng API cho thiết bị đeo có sẵn 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 API được thêm bằng addApiIfAvailable() không kết nối được do một lỗi không thể khôi phục (chẳng hạn như API_UNAVAILABLE cho Wear), API đó bị loại bỏ khỏi GoogleApiClient của bạn và ứng dụng tiếp tục đến 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 nào kèm theo lỗi có thể khôi phục (chẳng hạn như ý định giải quyết sự đồng ý của OAuth), thì thao tác kết nối ứng dụng không thành công. Thời gian 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 đó khi có thể. Khi sử dụng kết nối được quản lý thủ công ConnectionResult chứa ý định giải quyết là được gửi tới lệnh gọi lại onConnectionFailed(). API lỗi kết nối sẽ chỉ bị bỏ qua nếu không có giải pháp cho lỗi này và API đã được thêm vào cùng với addApiIfAvailable(). Để tìm hiểu cách triển khai lỗi kết nối thủ công hãy xem phần Xử lý lỗi kết nối.

Bởi vì API được thêm bằng addApiIfAvailable() không phải lúc nào cũng có mặt trong ứng dụng được kết nối Thực thể của GoogleApiClient, 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 sử dụng hasConnectedApi(). Để tìm hiểu lý do 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() rồi nhận mã lỗi từ ConnectionResult. Nếu ứng dụng của bạn gọi một API khi API đó không phải như vậy kết nối với máy khách, cuộc gọi không thành công với API_NOT_AVAILABLE mã trạng thái.

Nếu API mà bạn đang thêm thông qua addApiIfAvailable() yêu cầu một hoặc bạn có thể thêm các phạm vi đó làm thông số trong Thay vì sử dụng lệnh gọi phương thức addApiIfAvailable() addScope(). Bạn có thể không yêu cầu được các phạm vi được thêm bằng phương pháp này nếu API kết nối không thành công trước khi nhận được sự đồng ý về 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 chỉ cho bạn cách sử dụng enableAutoManage để bắt đầu một kết nối được quản lý tự động kèm theo lỗi được khắc phục tự động. Gần như trong mọi trường hợp, đây là cách tốt nhất và dễ dàng nhất để kết nối với các API của Google từ Ứng dụng Android. Tuy nhiên, có một số trường hợp mà bạn vẫn muốn sử dụng kết nối được quản lý thủ công với API Google trong ứng dụng của bạn:

  • Để 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 API kết nối
  • Để 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 kết nối được quản lý theo cách thủ công vớ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 lệnh gọi lại để phản hồi việc không đồng bộ connect() 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 hàm connect()disconnect() vào đúng thời điểm trong vòng đời của ứng dụng. Trong một hoạt động ngữ cảnh thì tốt nhất là gọi connect() trong onStart() của hoạt động và disconnect() trong phương thức onStop() của hoạt động. connect()disconnect() phương thức tự động được gọi 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, bạn có thể 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 một cuộc gọi tới onConnectionFailed() với SIGN_IN_REQUIRED vì tài khoản người dùng không được chỉ định.

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

Khi ứng dụng nhận được lệnh gọi đến onConnectionFailed() gọi lại, bạn nên gọi hasResolution() trên ConnectionResult được cung cấp . Nếu giá trị trả về là true, ứng dụng của bạn có thể yêu cầu người dùng thực hiện ngay hành động để giải quyết lỗi bằng cách đang 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 ngữ 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ề false, ứng dụng của bạn sẽ gọi GoogleApiAvailability.getErrorDialog()! hãy 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 Google Play cung cấp dịch vụ phù hợp với lỗi. Hộp thoại này có thể chỉ cung cấp thông báo giải thích lỗi, hoặc cũng có thể cung cấp 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ụ: Bây giờ, phương thức gọi lại onConnectionFailed() 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() hoặc loại bỏ thông báo do GoogleApiAvailability.getErrorDialog() cung cấp, hoạt động của bạn sẽ nhận được onActivityResult() lệnh gọi lại bằng RESULT_OK mã kết quả. Khi đó, ứng dụng của bạn có thể gọi connect() một lần nữa. 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. Việc này giúp theo dõi trạng thái của ứng dụng trong khi người dùng đang giải quyết lỗi để tránh lặp lại các nỗ lực giải quyết cùng một lỗi . Ví dụ: mặc dù hộp thoại chọn tài khoản được hiển thị để giúp người dùng giải quyết SIGN_IN_REQUIRED lỗi, người dùng có thể xoay màn hình. Việc này sẽ tạo lại hoạt động của bạn và khiến onStart() cần được được gọi lại, sau đó cuộc gọi sẽ được connect(). Chiến dịch này dẫn đến một cuộc gọi khác đến startResolutionForResult()! Thao tác này sẽ tạo một hộp thoại chọn tài khoản khác phía trước một 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 khác của người dùng hoặc các sự kiện 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() trong khi quá trình khắc phục lỗi đang diễn ra trước đó, bạn cần giữ lại giá trị 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 onActivityResult() hãy đặt giá trị 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), lưu boolean trong 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 đó, 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.