גישה ל-Google APIs באמצעות GoogleApiClient (הוצא משימוש)

אפשר להשתמש ב-GoogleApiClient ('לקוח Google API') אובייקט לצורך גישה לממשקי ה-API של Google שסופקו בספריית Google Play Services (למשל 'כניסה באמצעות חשבון Google', 'משחקים' ו-Drive). לקוח Google API מספק נקודת כניסה נפוצה ל-Google Play Services ומנהלת את הרשת בין המכשיר של המשתמש לכל אחד משירותי Google.

עם זאת, בממשק החדש יותר של GoogleApi וההטמעות שלו קל יותר הן הדרך המועדפת לגשת לממשקי ה-API של Play Services. למידע נוסף, ראו גישה ל-Google APIs.

במדריך הזה תלמדו:

  • ניהול אוטומטי של החיבור אל Google Play Services.
  • לבצע קריאות סינכרוניות ואסינכרוניות ל-API לכל אחד משירותי Google Play.
  • ניהול ידני של החיבור ל-Google Play Services במקרים הנדירים שבהם הנחוצים. למידע נוסף על חיבורים שמנוהלים באופן ידני
איור 1: איור שמראה איך לקוח Google API מספק הוא ממשק שמיועד לחיבור ולביצוע שיחות לכל אחד משירותי Google Play הזמינים, כמו Google Play Games ו-Google Drive.

כדי להתחיל, קודם עליך להתקין את ספריית שירותי Google Play (גרסה 15 ואילך) ל-Android SDK. אם עדיין לא עשית זאת, עליך לפעול לפי ההוראות המפורטות ב- כך מגדירים את Google Play Services SDK

הפעלת חיבור שמנוהל באופן אוטומטי

אחרי שמקשרים את הפרויקט לספריית Google Play Services, יוצרים מופע של GoogleApiClient באמצעות GoogleApiClient.Builder ממשקי API של הפעילות שלך onCreate() . GoogleApiClient.Builder בקטגוריה הזו יש שיטות שמאפשרות לכם לציין את ממשקי ה-API של Google שבהם אתם רוצים להשתמש היקפי הרשאות OAuth 2.0. כאן יש דוגמה לקוד שיוצר מופע GoogleApiClient שמתחבר לשירות Google Drive:

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

אפשר להוסיף כמה ממשקי API ומספר היקפים לאותו מוצר GoogleApiClient על ידי הוספת קריאות נוספות ל-addApi() ו-addScope().

חשוב: אם אתם מוסיפים את ה-API של Wearable עם ממשקי API אחרים, GoogleApiClient, יכול להיות שתיתקלו בשגיאות חיבור של לקוח במכשירים כן לא מותקנת בהם האפליקציה ל-Wear OS. שפת תרגום להימנע משגיאות חיבור, מפעילים את השיטה addApiIfAvailable() ומעבירים את ה-API של Wearable כדי לאפשר ללקוח לטפל באלגנטיות API. מידע נוסף זמין במאמר בנושא גישה ל-Wearable API.

כדי להתחיל חיבור שמנוהל באופן אוטומטי, עליך לציין הטמעה של OnConnectionFailedListener לקבלת שגיאות חיבור שלא ניתן לפתור. כשחשבון בניהול אוטומטי המכונה של GoogleApiClient מנסה להתחבר ל-Google APIs, תצוגה בממשק המשתמש כדי לנסות לתקן כשלים בחיבור שניתן לפתור (לדוגמה, צריך לעדכן את Google Play Services). אם מתרחשת שגיאה שאי אפשר נפתרו, תקבלו שיחה אל onConnectionFailed()

אפשר גם לציין הטמעה אופציונלית של הממשק ConnectionCallbacks אם האפליקציה צריכה לדעת מתי חיבור שמנוהל באופן אוטומטי נוצר או מושעה. לדוגמה אם שהאפליקציה שלך מבצעת קריאות לכתיבת נתונים ל-Google APIs, יש להפעיל אותן רק אחרי הקריאה ל-method onConnected().

לפניכם פעילות לדוגמה שבה אנחנו מיישמים את ממשקי הקריאה החוזרת ומוסיפה אותם ללקוח 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

        // ...
    }
}

המכונה של GoogleApiClient תתחבר באופן אוטומטי אחרי הפעילות מתקשרת onStart() ומתנתקים אחרי השיחה ל-onStop(). האפליקציה שלך יכולה להתחיל מיד ליצור בקשות קריאה ל-Google APIs אחרי פיתוח של GoogleApiClient, בלי בהמתנה להשלמת החיבור.

תקשורת עם שירותי Google

לאחר ההתחברות, הלקוח שלך יכול לבצע קריאות לקריאה ולכתיבה באמצעות ממשקי ה-API שספציפיים לשירות עבור שהאפליקציה שלך מורשית לקבל, כפי שצוין על ידי ממשקי ה-API וההיקפים שהוספת מופע GoogleApiClient.

הערה: לפני שמבצעים שיחות לשירותי Google ספציפיים, יכול להיות שיהיה צורך לרשום את ב-Google Developer Console. לקבלת הוראות, אפשר לעיין המדריך המלא ל-API שבו אתם משתמשים, כמו Google Drive או כניסה באמצעות חשבון Google.

כשמבצעים בקשת קריאה או כתיבה באמצעות GoogleApiClient, לקוח ה-API מחזיר אובייקט PendingResult שמייצג את הבקשה. הפעולה הזו מתבצעת מיד, לפני שהבקשה נשלחת לשירות Google שאליו האפליקציה מתקשרת.

לדוגמה, הנה בקשה לקרוא קובץ מ-Google Drive שמספק אובייקט PendingResult:

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

אחרי שלאפליקציה יש אובייקט PendingResult, לאחר מכן האפליקציה תוכל לציין אם הבקשה תטופל כשיחה אסינכרונית או כשיחה מסונכרנת.

טיפ: האפליקציה שלכם יכולה להוסיף בקשות קריאה לתור כשהיא לא מחוברת לשירותי Google Play. עבור לדוגמה, האפליקציה שלכם יכולה לקרוא ל-methods לקריאת קובץ מ-Google Drive גם אם המכונה GoogleApiClient עדיין מחוברת. לאחר יצירת חיבור, מופעלות בקשות קריאה שמופיעות בתור. בקשות כתיבה יוצרות שגיאה אם האפליקציה קוראת שיטות הכתיבה של Google Play Services כשלקוח Google API לא מחובר.

שימוש בשיחות אסינכרוניות

כדי להפוך את הבקשה לאסינכרונית, צריך להתקשר setResultCallback() ב-PendingResult ולספק יישום של ממשק ResultCallback. עבור הנה הבקשה שמופעלת באופן אסינכרוני:

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

כשהאפליקציה מקבלת אובייקט Result ב- הקריאה החוזרת onResult(), הוא נשלח כמופע של מחלקה המשנה המתאימה כפי שצוין על ידי ה-API שבו אתם משתמשים, כמו DriveApi.MetadataBufferResult.

שימוש בשיחות סינכרוניות

אם אתם רוצים שהקוד יפעל לפי סדר מוגדר בלבד, אולי בגלל שהתוצאה נדרשת כארגומנט ארגומנט אחר. אפשר להפוך את הבקשה לסינכרונית באמצעות await() ב- PendingResult השרשור ייחסם ומחזירה את האובייקט Result בתהליך השלמת הבקשה. האובייקט הזה מוצג כמופע של קטגוריית המשנה המתאימה כפי שצוין על ידי ממשק ה-API שבו אתם משתמשים. לדוגמה, DriveApi.MetadataBufferResult

כי התקשרות אל await() תחסום את השרשור עד לקבלת התוצאה, האפליקציה לעולם לא תשלח בקשות סינכרוניות אל Google APIs שרשור בממשק המשתמש. האפליקציה שלכם יכולה ליצור שרשור חדש באמצעות אובייקט AsyncTask ולהשתמש בשרשור הזה כדי ליצור את הבקשה הסנכרנת.

הדוגמה הבאה מראה איך לשלוח בקשת קובץ ל-Google Drive כקריאה מסונכרנת:

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

גישה ל-API הלביש

Wearable API מספק ערוץ תקשורת לאפליקציות שפועלות במכשירים ניידים ובמכשירים לבישים. ה-API מורכב מקבוצה של אובייקטי נתונים שהמערכת יכולה לשלוח ולסנכרן, וגם מאזינים שמאפשרים לאפליקציות שלכם לקבל הודעות על אירועים חשובים באמצעות שכבת נתונים. Wearable API זמין במכשירים עם Android בגרסה 4.3 (רמת API 18) ומעלה כאשר חובר מכשיר לביש והאפליקציה הנלווית של Wear OS מותקנת במכשיר.

שימוש ב-Wearable API באופן עצמאי

אם האפליקציה שלך משתמשת ב-Wearable API אבל לא ב-Google APIs אחרים, אפשר להוסיף את ה-API הזה על ידי קוראים לשיטה addApi(). הדוגמה הבאה מראה איך להוסיף את המאפיין Wearable API למופע של GoogleApiClient:

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

במצבים שבהם Wearable API לא זמין, המערכת מבקשת חיבור הכללת Wearable API תיכשל עם הפרמטר API_UNAVAILABLE קוד שגיאה.

אפשר להיעזר בדוגמה הבאה כדי לבדוק אם Wearable API זמין:

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

שימוש ב-API הלביש עם ממשקי API אחרים של Google

אם האפליקציה שלך משתמשת ב-Wearable API בנוסף לממשקי API אחרים של Google, צריך לקרוא אל addApiIfAvailable() ומעבירים את הנתונים ב-Wearable API כדי לבדוק אם הם זמינים. תוכלו להשתמש בבדיקה הזו כדי לעזור לאפליקציה לטפל בצורה חלקה במקרים שבהם ה-API לא זמין.

בדוגמה הבאה ניתן לראות איך לגשת ל-Wearable API יחד עם 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();

בדוגמה שלמעלה, GoogleApiClient יכול להתחבר בהצלחה אל Google Drive בלי להתחבר ל-Wearable API אם הוא לא זמין. אחרי מחברים את GoogleApiClient חשוב לוודא ש-Wearable API זמין לפני שמבצעים את הקריאות ל-API:

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

התעלמות מכשלים בחיבור ל-API

אם התקשרות אל addApi() וה-GoogleApiClient לא יכול להתחבר בהצלחה ל-API הזה, כל פעולת החיבור של הלקוח תיכשל מפעיל את הקריאה החוזרת (callback) של onConnectionFailed().

אפשר לרשום כשל בחיבור API שהמערכת תתעלם ממנו באמצעות addApiIfAvailable() אם נוסף API עם החיבור של addApiIfAvailable() נכשל עקב שגיאה שבעקבותיה אי אפשר לשחזר (כמו API_UNAVAILABLE ל-Wear), ה-API הזה מושמט מה-GoogleApiClient והלקוח ממשיך אל להתחבר לממשקי API אחרים. אבל, אם חיבור כלשהו ל-API נכשל עם שגיאה שניתנת לשחזור (כמו Intent לפתרון הסכמה ב-OAuth), פעולת החיבור של הלקוח נכשלת. מתי באמצעות חיבור שמנוהל באופן אוטומטי, GoogleApiClient ינסה כדי לפתור שגיאות כאלה ככל האפשר. כשמשתמשים בחיבור שמנוהל באופן ידני ConnectionResult שמכיל כוונה לפתרון הוא נמסרו לקריאה החוזרת (callback) של onConnectionFailed(). API המערכת מתעלמת מכשלים בחיבור רק אם אין פתרון לכשל והוספה של API עם addApiIfAvailable(). כדי ללמוד איך להטמיע כשל בחיבור ידני בטיפול, ראו טיפול בכשלים בחיבור.

כי נוספו ממשקי API עם יכול להיות שהערוץ addApiIfAvailable() לא תמיד יופיע מחוברים GoogleApiClient, עליכם להגן על קריאות לממשקי ה-API האלה על ידי הוספת בדיקה באמצעות hasConnectedApi(). כדי לברר מדוע נכשל הניסיון להתחבר ל-API מסוים כאשר כל פעולת החיבור הצליחה עבור הלקוח, ניתן לקרוא getConnectionResult() ומקבלים את קוד השגיאה אובייקט ConnectionResult. אם הלקוח שלכם קורא ל-API כשהוא לא זמין מחוברת ללקוח, הקריאה תיכשל API_NOT_AVAILABLE קוד הסטטוס.

אם ב-API שאתם מוסיפים דרך addApiIfAvailable() נדרש מוסיפים את ההיקפים האלה כפרמטרים להפעיל את ה-method addApiIfAvailable() במקום להשתמש addScope(). ייתכן שלא יישלחו בקשות להיקפי הרשאות שנוספו בגישה הזו אם ה-API החיבור נכשל לפני קבלת הסכמת OAuth, ואילו היקפי הרשאות שנוספו עם addScope() הם תמיד בקשות.

חיבורים שמנוהלים באופן ידני

רוב המדריך הזה מראה איך להשתמש השיטה enableAutoManage כדי להתחיל חיבור שמנוהל באופן אוטומטי עם שגיאות שנפתרו באופן אוטומטי. בעוד בכל המקרים, זוהי הדרך הטובה והקלה ביותר להתחבר אל Google APIs אפליקציה ל-Android. עם זאת, יש מצבים מסוימים שבהם כדאי להשתמש חיבור שמנוהל באופן ידני ל-Google APIs באפליקציה שלכם:

  • לגשת אל Google APIs מחוץ לפעילות או לשלוט ב-API חיבור
  • כדי להתאים אישית את הטיפול בשגיאות חיבור והפתרון שלהן

בקטע הזה מפורטות דוגמאות לתרחישים כאלה ולתרחישים מתקדמים נוספים.

הפעלת חיבור שמנוהל באופן ידני

כדי להתחיל חיבור שמנוהל באופן ידני אל GoogleApiClient, צריך לציין הטמעה של ממשקי הקריאה החוזרת, ConnectionCallbacks ו-OnConnectionFailedListener. הממשקים האלה מקבלים קריאות חוזרות בתגובה connect() כאשר חיבור אל Google Play Services מצליח, נכשל או מושעה.

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

כשתנהל חיבור באופן ידני, תצטרך להפעיל את connect() וגם disconnect() מפורטות בנקודות הנכונות במחזור החיים של האפליקציה שלכם. בפעילות השיטה המומלצת היא לשלוח קריאה ל-connect() בonStart() של הפעילות שלכם ו-disconnect() בשיטה onStop() של הפעילות שלך. connect() וגם disconnect() אמצעי תשלום מופעלות אוטומטית כשמשתמשים בחיבור שמנוהל באופן אוטומטי.

אם אתם משתמשים ב-GoogleApiClient כדי להתחבר לממשקי API שדורשים אימות, כמו Google Drive או Google Play Games, יש סיכוי טוב ניסיון החיבור הראשון ייכשל והאפליקציה תתקשר אל onConnectionFailed() עם SIGN_IN_REQUIRED כי חשבון המשתמש לא צוין.

טיפול בכשלים בחיבור

כשהאפליקציה מקבלת שיחה אל onConnectionFailed() עליך להתקשר חזרה ל-hasResolution() בConnectionResult הנתון לאובייקט. אם הערך הוא True, האפליקציה יכולה לבקש מהמשתמש לבצע פעולה מיידית כדי לפתור את השגיאה עד שיחה startResolutionForResult() על האובייקט ConnectionResult. השיטה startResolutionForResult() פועל בדיוק כמו startActivityForResult() במצב הזה, והיא מפעילה פעילות שתואמת להקשר שעוזר למשתמש לפתור את השגיאה (למשל פעילות שעוזרת למשתמש בוחרים חשבון).

אם hasResolution() מחזירה False, האפליקציה צריכה לקרוא ל- GoogleApiAvailability.getErrorDialog(), ומעביר את קוד השגיאה לשיטה הזו. הפעולה הזו מחזירה Dialog סופק על ידי Google Play שמתאימים לשגיאה. יכול להיות שתיבת הדו-שיח תציג רק הודעה שמסבירה השגיאה, או שהוא יכול לכלול גם פעולה להפעלת פעילות שיכולה לפתור את השגיאה. (למשל, כשהמשתמש צריך להתקין גרסה חדשה יותר של Google Play Services).

לדוגמה, עכשיו שיטת הקריאה החוזרת onConnectionFailed() אמורה להיראות כך:

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

לאחר שהמשתמש מסיים את תיבת הדו-שיח שסופקה על ידי startResolutionForResult() או סוגר את ההודעה שניתנה על ידי GoogleApiAvailability.getErrorDialog(), הפעילות שלכם מקבלת onActivityResult() קריאה חוזרת (callback) באמצעות קוד תוצאה RESULT_OK. לאחר מכן האפליקציה יכולה להתקשר connect() שוב. לדוגמה:

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

בקוד שלמעלה, סביר להניח שהבחנתם בערך הבוליאני mResolvingError. כך אפשר לעקוב אחר את מצב האפליקציה בזמן שהמשתמש פותר את השגיאה כדי להימנע מניסיונות חוזרים לפתרון הבעיה שגיאה. לדוגמה, כשתיבת הדו-שיח של בורר החשבונות מוצגת כדי לעזור למשתמש לפתור את הבעיה SIGN_IN_REQUIRED שגיאה, המשתמש יכול לסובב את המסך. הפעולה הזו יוצרת מחדש את הפעילות וגורמת onStart() להתקשר שוב, ואז connect() שוב. הזה התוצאה תהיה קריאה נוספת אל startResolutionForResult(), שיוצרת תיבת דו-שיח נוספת של בורר חשבונות לפני תיבת הדו-שיח הקיימת.

ערך בוליאני זה משמש למטרה שלשמה הוא נועדו רק אם הוא ממשיך בכל המופעים של הפעילות. בקטע הבא מוסבר איך לשמור על מצב הטיפול בשגיאות באפליקציה, למרות פעולות אחרות של משתמשים או אירועים שמתרחשים במכשיר.

שמירה על המצב במהלך פתרון שגיאה

כדי להימנע מהרצת הקוד בזמן onConnectionFailed() בזמן שניסיון קודם לפתור שגיאה מתבצע, יש לשמור ערך בוליאני מציין אם האפליקציה כבר מנסה לפתור שגיאה.

כפי שמוצג בדוגמת הקוד שלמעלה, האפליקציה שלך צריכה להגדיר ערך בוליאני כ-true בכל פעם שהיא מבצעת startResolutionForResult() או מציג את תיבת הדו-שיח GoogleApiAvailability.getErrorDialog(). לאחר מכן, כשהאפליקציה מקבלת RESULT_OK ב- onActivityResult() קריאה חוזרת, מגדירים את הבוליאני ל-false.

כדי לעקוב אחר הערך הבוליאני בכל הפעלות מחדש (למשל, כאשר המשתמש מסובב את המסך), שומרים את הבוליאני בנתוני המכונה השמורים של הפעילות באמצעות 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);
}

לאחר מכן אפשר לשחזר את המצב שנשמר במהלך onCreate()

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

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

עכשיו הכול מוכן ואפשר להפעיל את האפליקציה באופן בטוח ולהתחבר באופן ידני אל Google Play Services.