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 API của Google") để 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 điểm truy cập chung vào Dịch vụ 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 hơn và cách triển khai giao diện này dễ sử dụng hơn và là cách ưu tiên để truy cập vào các API Dịch vụ Play. Xem bài viết Truy cập vào các API của Google.

Hướng dẫn này cho bạn biết 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 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ý kết nối với Dịch vụ Google Play theo cách thủ công trong những trường hợp hiếm hoi cần thiết. Để tìm hiểu thêm, hãy xem phần 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 API của Google cung cấp giao diện để kết nối và thực hiện lệnh gọi đế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. Nếu bạn chưa làm như vậy, hãy làm theo hướng dẫn trong phần Thiết lập SDK Dịch vụ Google Play.

Bắt đầu một 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ã 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 Wearable API cùng với các API khác vào GoogleApiClient, bạn có thể gặp lỗi kết nối ứng dụng trên các thiết bị không 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à truyền vào Wearable API để 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 phần Truy cập 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 một 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ố gắng kết nối với API của Google, thực thể này 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ể khắc phục (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 kết nối được quản lý tự động được thiết lập hoặc 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 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 các 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

        // ...
    }
}

Phiên bản GoogleApiClient sẽ tự động kết nối sau khi 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 tạo yêu cầu đọc cho các API của Google ngay sau khi tạo GoogleApiClient mà không cần chờ kết nối hoàn tất.

Giao tiếp 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 phải đăng ký ứng dụng của mình trong Google Developers Console. Để biết hướng dẫn, hãy tham khảo hướng dẫn bắt đầu phù 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ề một đối tượng PendingResult đại diện cho yêu cầu đó. Quá trình này diễn 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ó đối tượng PendingResult, ứng dụng có thể chỉ định 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ộ.

Mẹo: Ứ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 đã đưa vào hàng đợi sẽ thực thi. Yêu cầu ghi sẽ tạo 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 trong khi Ứng dụng Google API không được kết nối.

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

Để yêu cầu không đồng bộ, hãy gọi setResultCallback() trên PendingResult và cung cấp cách 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 đối tượng Result trong lệnh gọi lại onResult(), đối tượng này 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 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 muốn mã của mình 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 cần được dùng làm đối số cho một lệnh gọi khác, bạn có thể đồng bộ hoá yêu cầu 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ì việc gọi await() sẽ chặn luồng cho đến khi kết quả đến, nên ứng dụng của bạn không bao giờ đượ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 đối tượng AsyncTask và sử dụng luồng đó để tạo yêu cầu đồng bộ.

Ví dụ sau đây cho thấy cách tạo 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<String, Void, Void> {
    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 cung cấp một kênh giao tiếp 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 bằng cách sử dụng lớp dữ liệu. Wearable API 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à ứng dụng đồng hành Wear OS được cài đặt trên thiết bị.

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

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 đây 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 cho biết cách xác định xem API cho thiết bị đeo có được cung cấp 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 cùng với các API khác của Google, hãy gọi phương thức addApiIfAvailable() và truyền vào API cho thiết bị đeo để kiểm tra xem API đó có dùng được hay không. Bạn có thể sử dụng tính năng kiểm tra này để giúp ứng dụng của mình xử lý linh hoạt các trường hợp không có API.

Ví dụ sau đây cho thấy cách truy cập Wearable API cùng với Drive API:

// 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 API này không hoạt động. Sau khi bạn kết nối thực thể GoogleApiClient, hãy đảm bảo rằng Wearable API 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ý một lỗi kết nối API để 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 khôi phục được (chẳng hạn như API_UNAVAILABLE cho Wear), thì API đó sẽ bị xoá 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 bất kỳ kết nối API nào không thành công do lỗi có thể khôi phục (chẳng hạn như ý định giải quyết sự đồng ý OAuth), thì thao tác kết nối ứng dụng sẽ không thành công. Khi sử dụng một 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 sử dụng kết nối được quản lý theo cách thủ công, ConnectionResult chứa ý định phân giải sẽ được phân phối đến lệnh gọi lại onConnectionFailed(). Lỗi kết nối API chỉ bị bỏ qua nếu không có giải pháp cho lỗi đó và API được thêm bằng addApiIfAvailable(). Để tìm hiểu cách triển khai tính năng xử lý lỗi kết nối thủ công, hãy xem phần Xử lý lỗi kết nối.

Vì các API được thêm bằng addApiIfAvailable() không phải lúc nào cũng có trong thực thể GoogleApiClient đã kết nối, nên bạn nên bảo vệ các lệnh gọi đến các API này bằng cách thêm một bước kiểm tra bằng hasConnectedApi(). Để tìm hiểu lý do 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 cho ứng dụng, hãy gọi getConnectionResult() và lấy mã lỗi từ đối tượng ConnectionResult. Nếu ứng dụng gọi một API khi API đó chưa kết nối với ứng dụng, thì lệnh gọi sẽ không thực hiện được kèm theo 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 ý OAuth, trong khi các phạm vi được thêm bằng addScope() luôn được yêu cầu.

Kết nối được quản lý theo cách thủ công

Phần lớn 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 với các lỗi được tự động giải quyết. Trong hầu hết các trường hợp, đây là cách tốt nhất và dễ dàng nhất để kết nối với API của Google từ ứng dụng Android. Tuy nhiên, có một số trường hợp bạn muốn sử dụng kết nối được quản lý theo cách thủ công với API của Google trong ứng dụng:

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

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

Bắt đầu một 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 với GoogleApiClient, bạn phải chỉ định cách triển khai cho các 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 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 cần gọi các phương thức connect()disconnect() tại các thời đ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() sẽ 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, thì rất có thể lần kết nối đầu tiê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 của bạn nhận được 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 đượ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 hành động ngay để khắc phục lỗi bằng cách gọi startResolutionForResult() trên đối tượng ConnectionResult. Phương thức startResolutionForResult() 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 tài khoản).

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

Ví dụ: phương thức gọi lại onConnectionFailed() của bạn hiệ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() 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, có thể bạn đã nhận thấy boolean mResolvingError. Thao tác này theo dõi trạng thái ứng dụng trong khi người dùng đang khắc phục lỗi để tránh lặp lại các lần cố gắng khắc phục cùng một lỗi. Ví dụ: trong khi hộp thoại bộ chọn tài khoản hiển thị để giúp người dùng giải quyết lỗi SIGN_IN_REQUIRED, người dùng có thể xoay màn hình. Thao tá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(). Thao tác này dẫn đến một lệnh gọi khác đến startResolutionForResult(), tạo một hộp thoại chọn tài khoản khác trước hộp thoại hiện có.

Giá trị boolean này chỉ phục vụ mục đích dự kiến nếu giá trị này 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 hành động 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() trong khi một nỗ lực trước đó để giải quyết lỗi đang diễn ra, bạn cần giữ lại một boolean theo dõi xem ứng dụng của bạn có đang cố gắng giải quyết lỗi hay không.

Như 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 giá trị boolean thành false.

Để theo dõi boolean trên các lần khởi động lại hoạt động (chẳng hạn như khi người dùng xoay màn hình), hãy 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);
}

Giờ đây, bạn đã sẵn sàng chạy ứng dụng một cách an toàn và kết nối với Dịch vụ Google Play theo cách thủ công.