GoogleApiClient के साथ Google API तक ऐक्सेस करना (अब सेवा में नहीं है)

'Google Play सेवाएं' लाइब्रेरी (जैसे, 'Google साइन-इन', गेम, और Drive') में दिए गए Google API को ऐक्सेस करने के लिए, आपके पास GoogleApiClient ("Google API क्लाइंट") ऑब्जेक्ट का इस्तेमाल करने का विकल्प है. Google API क्लाइंट, Google Play सेवाओं के लिए एक सामान्य एंट्री पॉइंट उपलब्ध कराता है. साथ ही, उपयोगकर्ता के डिवाइस और Google की हर सेवा के बीच नेटवर्क कनेक्शन को मैनेज करता है.

हालांकि, GoogleApi के नए इंटरफ़ेस और इसे लागू करने के तरीके को इस्तेमाल करना आसान है. साथ ही, यह Play services के एपीआई को ऐक्सेस करने का पसंदीदा तरीका है. Google API ऐक्सेस करना देखें.

इस गाइड में बताया गया है कि ये काम कैसे किए जा सकते हैं:

  • Google Play services से, अपने कनेक्शन को अपने-आप मैनेज करने की सुविधा मिलती है.
  • किसी भी Google Play सेवा पर सिंक्रोनस और एसिंक्रोनस एपीआई कॉल करें.
  • बहुत कम मामलों में, Google Play services से अपने कनेक्शन को मैन्युअल तरीके से मैनेज करना ज़रूरी हो. ज़्यादा जानने के लिए, मैन्युअल तरीके से मैनेज किए जाने वाले कनेक्शन देखें.
पहली इमेज: एक इलस्ट्रेशन, जिसमें दिखाया गया है कि Google API क्लाइंट, Google Play Games और Google Drive जैसी Google Play की उपलब्ध सेवाओं में से किसी से भी कनेक्ट करने और कॉल करने के लिए इंटरफ़ेस कैसे उपलब्ध कराता है.

शुरू करने के लिए, पहले आपको अपने Android SDK टूल के लिए Google Play services की लाइब्रेरी (बदलाव 15 या उसके बाद का वर्शन) इंस्टॉल करनी होगी. अगर आपने पहले से ऐसा नहीं किया है, तो Google Play सेवाएं SDK टूल सेट अप करें में दिए गए निर्देशों का पालन करें.

अपने-आप मैनेज होने वाला कनेक्शन शुरू करना

जब आपका प्रोजेक्ट Google Play services की लाइब्रेरी से लिंक हो जाए, तब अपनी गतिविधि के onCreate() तरीके में GoogleApiClient.Builder एपीआई का इस्तेमाल करके, GoogleApiClient का इंस्टेंस बनाएं. GoogleApiClient.Builder क्लास में ऐसे तरीके बताए गए हैं जिनसे आपको, इस्तेमाल किए जाने वाले Google API और अपने हिसाब से OAuth 2.0 स्कोप तय करने में मदद मिलती है. यहां कोड का एक उदाहरण दिया गया है, जो Google Drive सेवा से कनेक्ट करने वाला GoogleApiClient इंस्टेंस बनाता है:

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

एक ही GoogleApiClient में कई एपीआई और कई स्कोप जोड़े जा सकते हैं. ऐसा करने के लिए, addApi() और addScope() में अतिरिक्त कॉल जोड़ें.

अहम जानकारी: अगर Wearable एपीआई को अन्य एपीआई के साथ GoogleApiClient में जोड़ा जा रहा है, तो आपको उन डिवाइसों पर क्लाइंट कनेक्शन से जुड़ी गड़बड़ियां दिख सकती हैं जिनमें Wear OS ऐप्लिकेशन इंस्टॉल नहीं है. कनेक्शन की गड़बड़ियों से बचने के लिए, addApiIfAvailable() तरीके को कॉल करें और Wearable एपीआई में पास करें. इससे आपका क्लाइंट, एपीआई के मौजूद डेटा को सही तरीके से मैनेज कर पाएगा. ज़्यादा जानकारी के लिए, Wearable API ऐक्सेस करना देखें.

अपने-आप मैनेज होने वाला कनेक्शन शुरू करने के लिए, आपको OnConnectionFailedListener इंटरफ़ेस के लिए, लागू करने का तरीका तय करना होगा, ताकि कनेक्शन से जुड़ी ऐसी गड़बड़ियां मिल सकें जिन्हें ठीक नहीं किया जा सकता. जब अपने-आप मैनेज होने वाले GoogleApiClient इंस्टेंस को Google API से कनेक्ट करने की कोशिश की जाती है, तो यह अपने-आप यूज़र इंटरफ़ेस (यूआई) दिखाएगा, ताकि हल किए जा सकने वाले कनेक्शन की गड़बड़ी को ठीक करने की कोशिश की जा सके. उदाहरण के लिए, अगर Google Play services को अपडेट करने की ज़रूरत है. अगर कोई ऐसी गड़बड़ी होती है जिसे ठीक नहीं किया जा सकता, तो आपको onConnectionFailed() पर कॉल किया जाएगा.

अगर आपके ऐप्लिकेशन को यह जानना ज़रूरी है कि अपने-आप मैनेज होने वाला कनेक्शन कब जोड़ा गया या निलंबित किया गया, तो ConnectionCallbacks इंटरफ़ेस को लागू करना ज़रूरी नहीं है. ऐसा भी किया जा सकता है. उदाहरण के लिए, अगर आपका ऐप्लिकेशन Google API को डेटा लिखने के लिए कॉल करता है, तो इन्हें सिर्फ़ 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() को कॉल करने के बाद डिसकनेक्ट हो जाएगा. आपका ऐप्लिकेशन, GoogleApiClient बनाने के तुरंत बाद, Google API को पढ़ने का अनुरोध करना शुरू कर सकता है. ऐसा, कनेक्शन के पूरा होने का इंतज़ार किए बिना किया जा सकता है.

Google की सेवाओं से संपर्क करना

कनेक्ट करने के बाद, आपका क्लाइंट सेवा के लिए खास तौर पर बने एपीआई का इस्तेमाल करके, पढ़ने और लिखने के लिए कॉल कर सकता है. आपके ऐप्लिकेशन को इनके लिए अनुमति मिली हुई है, जैसा कि आपके GoogleApiClient इंस्टेंस में जोड़े गए एपीआई और दायरों में बताया गया है.

ध्यान दें: Google की खास सेवाओं के लिए कॉल करने से पहले, आपको सबसे पहले Google Developer Console में अपना ऐप्लिकेशन रजिस्टर करना होगा. निर्देशों के लिए, इस्तेमाल किए जा रहे एपीआई के लिए शुरुआती निर्देश देखें. जैसे, Google Drive या Google साइन इन.

जब GoogleApiClient का इस्तेमाल करके, पढ़ने या लिखने का अनुरोध किया जाता है, तो एपीआई क्लाइंट एक 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 services से कनेक्ट न होने पर भी, आपका ऐप्लिकेशन पढ़ने के अनुरोध को सूची में डाल सकता है. उदाहरण के लिए, आपका ऐप्लिकेशन Google Drive से फ़ाइल पढ़ने के तरीकों को कॉल कर सकता है. भले ही, आपका GoogleApiClient इंस्टेंस अभी तक कनेक्ट हो या नहीं. कनेक्शन बन जाने के बाद, कतार में शामिल किए गए रीड रिक्वेस्ट लागू होते हैं. अगर आपका ऐप्लिकेशन, Google API क्लाइंट के कनेक्ट न होने पर Google Play services को कॉल करने के तरीकों को कॉल करता है, तो 'अनुरोध लिखें' गड़बड़ी जनरेट होती है.

एसिंक्रोनस कॉल का इस्तेमाल करना

अनुरोध को एसिंक्रोनस बनाने के लिए, PendingResult पर setResultCallback() को कॉल करें और 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.
            // ...
        }
    });
}

जब आपके ऐप्लिकेशन को onResult() कॉलबैक में Result ऑब्जेक्ट मिलता है, तो उसे एपीआई की बताई गई सही सब-क्लास के इंस्टेंस के तौर पर डिलीवर किया जाता है. जैसे, DriveApi.MetadataBufferResult.

सिंक्रोनस कॉल का उपयोग करना

अगर आपको अपने कोड को पूरी तरह तय किए गए क्रम में लागू करना है, तो यह हो सकता है कि एक कॉल की वजह से, दूसरे कॉल पर तर्क करने के लिए, उस कॉल की ज़रूरत हो. ऐसे में, PendingResult पर await() को कॉल करके, अपने अनुरोध को सिंक किया जा सकता है. यह थ्रेड को ब्लॉक करता है और अनुरोध पूरा होने पर Result ऑब्जेक्ट दिखाता है. इस ऑब्जेक्ट को सही सब-क्लास के इंस्टेंस के तौर पर डिलीवर किया जाता है. ऐसा, आपके इस्तेमाल किए जा रहे एपीआई से तय किए गए उदाहरण के मुताबिक किया जाता है, जैसे कि DriveApi.MetadataBufferResult.

await() को कॉल करने से थ्रेड ब्लॉक रहती है, जब तक नतीजा नहीं आता. इसलिए, आपके ऐप्लिकेशन को कभी भी यूज़र इंटरफ़ेस (यूआई) थ्रेड पर Google API को सिंक्रोनस अनुरोध नहीं करना चाहिए. आपका ऐप्लिकेशन, 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
        // ...
    }
}

पहने जाने वाले डिवाइसों के लिए एपीआई ऐक्सेस करें

Wearable API, हैंडहेल्ड और पहने जाने वाले डिवाइसों पर काम करने वाले ऐप्लिकेशन के लिए कम्यूनिकेशन चैनल उपलब्ध कराता है. इस एपीआई में डेटा ऑब्जेक्ट का एक सेट होता है, जिसे सिस्टम भेज सकता है और सिंक कर सकता है. साथ ही, इस एपीआई में ऐसे डेटा ऑब्जेक्ट होते हैं जो डेटा लेयर का इस्तेमाल करके, आपके ऐप्लिकेशन को अहम इवेंट की सूचना देते हैं. Wearable API, Android 4.3 (एपीआई लेवल 18) या इसके बाद के वर्शन वाले डिवाइसों पर तब उपलब्ध होता है, जब पहने जाने वाले डिवाइस को कनेक्ट किया गया हो और उस पर Wear OS साथी ऐप्लिकेशन इंस्टॉल किया गया हो.

Wearable API का स्टैंड-अलोन इस्तेमाल करना

अगर आपके ऐप्लिकेशन में Google API के बजाय, Wearable API का इस्तेमाल किया जा रहा है, तो इस एपीआई को जोड़ा जा सकता है. इसके लिए, addApi() वाला तरीका कॉल करें. यहां दिए गए उदाहरण में, अपने GoogleApiClient इंस्टेंस में Wearable API को जोड़ने का तरीका बताया गया है:

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

अन्य Google API के साथ Wearable API का इस्तेमाल करना

अगर आपके ऐप्लिकेशन में Google के अन्य एपीआई के अलावा, Wearable API का इस्तेमाल किया जाता है, तो यह देखने के लिए कि आपका ऐप्लिकेशन उपलब्ध है या नहीं, addApiIfAvailable() वाला तरीका इस्तेमाल करें और Wearable API में पास करें. एपीआई के उपलब्ध न होने के मामलों में, अपने ऐप्लिकेशन को बेहतर तरीके से मैनेज करने के लिए, इस जांच की सुविधा का इस्तेमाल किया जा सकता है.

यहां दिए गए उदाहरण में, Drive API के साथ-साथ Wearable 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 उपलब्ध नहीं है, तो Wearable API से कनेक्ट किए बिना ही GoogleApiClient को Google Drive से कनेक्ट किया जा सकता है. अपना GoogleApiClient इंस्टेंस कनेक्ट करने के बाद, एपीआई कॉल करने से पहले पक्का करें कि Wearable API उपलब्ध है:

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

एपीआई कनेक्शन की असफलताओं को अनदेखा करना

अगर addApi() को कॉल किया जाता है और GoogleApiClient उस एपीआई से कनेक्ट नहीं हो पाता है, तो उस क्लाइंट के लिए पूरा कनेक्शन काम नहीं करेगा और onConnectionFailed() कॉलबैक को ट्रिगर करेगा.

addApiIfAvailable() का इस्तेमाल करके, एपीआई कनेक्शन के काम न करने पर, उसे अनदेखा करने के लिए रजिस्टर किया जा सकता है. अगर addApiIfAvailable() के साथ जोड़ा गया कोई एपीआई, वापस न लाई जा सकने वाली किसी गड़बड़ी (जैसे, Wear के लिए API_UNAVAILABLE) की वजह से कनेक्ट नहीं हो पाता है, तो उस एपीआई को आपके GoogleApiClient से हटा दिया जाता है और क्लाइंट उसे अन्य एपीआई से कनेक्ट करता है. हालांकि, अगर एपीआई कनेक्शन ऐसी गड़बड़ी (जैसे कि OAuth के लिए सहमति रिज़ॉल्यूशन इंटेंट) की वजह से काम नहीं करता जिसे वापस नहीं पाया जा सकता, तो क्लाइंट कनेक्ट करने की कार्रवाई पूरी नहीं हो पाती. अपने-आप मैनेज होने वाले कनेक्शन का इस्तेमाल करने पर, GoogleApiClient जब भी संभव होगा, ऐसी गड़बड़ियों को ठीक करने की कोशिश करेगा. मैन्युअल तरीके से मैनेज किए गए कनेक्शन का इस्तेमाल करने पर, रिज़ॉल्यूशन इंटेंट वाला ConnectionResult onConnectionFailed() कॉलबैक को डिलीवर किया जाता है. एपीआई कनेक्शन की गड़बड़ियों को सिर्फ़ तब अनदेखा किया जाता है, जब समस्या का कोई समाधान न हो और एपीआई को addApiIfAvailable() के साथ जोड़ा गया हो. मैन्युअल रूप से कनेक्ट न हो पाने की समस्या को हैंडल करने का तरीका जानने के लिए, कनेक्शन के काम न करने की वजहों को मैनेज करना लेख पढ़ें.

ऐसा हो सकता है कि addApiIfAvailable() की मदद से जोड़े गए एपीआई, कनेक्ट किए गए GoogleApiClient इंस्टेंस में हमेशा मौजूद न हों. इसलिए, आपको hasConnectedApi() का इस्तेमाल करके, इन एपीआई के लिए जांच जोड़ना चाहिए. यह पता लगाने के लिए कि क्लाइंट के लिए, कनेक्शन की पूरी कार्रवाई पूरी हो जाने पर कोई खास एपीआई कनेक्ट क्यों नहीं हो सका, getConnectionResult() को कॉल करें और ConnectionResult ऑब्जेक्ट से गड़बड़ी कोड पाएं. अगर आपका क्लाइंट, क्लाइंट से कनेक्ट न होने पर किसी एपीआई को कॉल करता है, तो API_NOT_AVAILABLE स्टेटस कोड के साथ कॉल नहीं हो पाता.

जिस एपीआई को addApiIfAvailable() के ज़रिए जोड़ा जा रहा है, अगर उसे एक या उससे ज़्यादा स्कोप की ज़रूरत है, तो addScope() तरीके का इस्तेमाल करने के बजाय, अपने addApiIfAvailable() मेथड कॉल में उन स्कोप को पैरामीटर के तौर पर जोड़ें. अगर OAuth के लिए सहमति मिलने से पहले एपीआई कनेक्शन काम नहीं करता, तो इस तरीके का इस्तेमाल करके जोड़े गए स्कोप के लिए अनुरोध नहीं किया जा सकता. वहीं, addScope() की मदद से जोड़े गए स्कोप का हमेशा अनुरोध किया जाता है.

मैन्युअल रूप से मैनेज किए जाने वाले कनेक्शन

इस गाइड के ज़्यादातर हिस्से में, enableAutoManage तरीके का इस्तेमाल करके, अपने-आप ठीक होने वाली गड़बड़ियों के साथ, अपने-आप मैनेज होने वाले कनेक्शन को शुरू करने का तरीका बताया गया है. करीब-करीब सभी मामलों में, यह अपने Android ऐप्लिकेशन से Google API से कनेक्ट करने का सबसे अच्छा और आसान तरीका है. हालांकि, कुछ स्थितियां ऐसी भी होती हैं जिनमें आप अपने ऐप्लिकेशन में Google API के लिए मैन्युअल रूप से मैनेज किए गए कनेक्शन का इस्तेमाल करना चाहेंगे:

  • किसी गतिविधि के बाहर Google API को ऐक्सेस करने या एपीआई कनेक्शन का कंट्रोल बनाए रखने के लिए
  • कनेक्शन की गड़बड़ी को हैंडल करने और उसके रिज़ॉल्यूशन को पसंद के मुताबिक बनाने के लिए

इस सेक्शन में, ऐसे उदाहरण के साथ-साथ इस्तेमाल के अन्य बेहतर उदाहरणों की जानकारी दी गई है.

मैन्युअल तरीके से मैनेज किया जा रहा कनेक्शन शुरू करें

GoogleApiClient से मैन्युअल तरीके से मैनेज किया जाने वाला कनेक्शन शुरू करने के लिए, आपको कॉलबैक इंटरफ़ेस ConnectionCallbacks और OnConnectionFailedListener को लागू करने की जानकारी देनी होगी. Google Play services से कनेक्ट होने, कामयाब होने या निलंबित होने पर, इन इंटरफ़ेस को एसिंक्रोनस connect() तरीके की वजह से कॉलबैक मिलते हैं.

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

किसी कनेक्शन को मैन्युअल तरीके से मैनेज करते समय, आपको अपने ऐप्लिकेशन की लाइफ़साइकल में, connect() और disconnect() सही समय पर, सही तरीकों को कॉल करना होगा. गतिविधि के बारे में सबसे सही तरीका यह है कि आप गतिविधि के onStart() तरीके से connect() को और गतिविधि के onStop() तरीके से disconnect() को कॉल करें. अपने-आप मैनेज होने वाले कनेक्शन का इस्तेमाल करने पर, connect() और disconnect() के तरीके अपने-आप कॉल हो जाते हैं.

अगर GoogleApiClient का इस्तेमाल उन एपीआई से कनेक्ट करने के लिए किया जा रहा है जिनकी पुष्टि की ज़रूरत होती है, जैसे कि Google Drive या Google Play Games, तो इस बात की संभावना है कि आपका पहला कनेक्शन काम नहीं कर पाए. साथ ही, आपके ऐप्लिकेशन को SIGN_IN_REQUIRED गड़बड़ी के साथ onConnectionFailed() पर कॉल आएगा, क्योंकि उपयोगकर्ता खाते के बारे में जानकारी नहीं दी गई थी.

कनेक्शन से जुड़ी गड़बड़ियां ठीक करना

जब आपके ऐप्लिकेशन को onConnectionFailed() कॉलबैक के लिए कॉल आता है, तो आपको दिए गए ConnectionResult ऑब्जेक्ट पर hasResolution() को कॉल करना चाहिए. अगर यह वैल्यू 'सही' दिखाता है, तो आपका ऐप्लिकेशन उपयोगकर्ता से यह अनुरोध कर सकता है कि वह ConnectionResult ऑब्जेक्ट पर startResolutionForResult() को कॉल करके, गड़बड़ी को ठीक करने के लिए तुरंत कार्रवाई करे. इस स्थिति में, startResolutionForResult() का तरीका startActivityForResult() की तरह ही काम करता है. साथ ही, यह कॉन्टेक्स्ट के हिसाब से एक ऐसी गतिविधि लॉन्च करता है जिससे उपयोगकर्ता को गड़बड़ी ठीक करने में मदद मिलती है. जैसे, कोई ऐसी गतिविधि जो उपयोगकर्ता को खाता चुनने में मदद करती है.

अगर hasResolution() 'गलत' दिखाता है, तो आपके ऐप्लिकेशन को GoogleApiAvailability.getErrorDialog() को कॉल करना चाहिए. साथ ही, इस तरीके में गड़बड़ी का कोड पास करना चाहिए. ऐसा करने पर, Google Play services से मिला Dialog दिखता है, जो गड़बड़ी के लिहाज़ से सही होता है. इस डायलॉग बॉक्स में, गड़बड़ी के बारे में सिर्फ़ एक मैसेज दिया जा सकता है या गड़बड़ी को ठीक करने वाली गतिविधि शुरू करने के लिए कार्रवाई की जा सकती है. जैसे, जब उपयोगकर्ता को 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() से मिले मैसेज को खारिज कर देता है, तब आपकी गतिविधि को RESULT_OK नतीजे के कोड के साथ onActivityResult() कॉलबैक मिलता है. इसके बाद, आपका ऐप्लिकेशन 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() में कोड को एक्ज़ीक्यूट करने से रोकने के लिए, आपको एक बूलियन बनाए रखना होगा. इससे यह ट्रैक किया जा सकेगा कि आपका ऐप्लिकेशन, पहले से ही किसी गड़बड़ी को ठीक करने की कोशिश कर रहा है या नहीं.

जैसा कि ऊपर दिए गए कोड के उदाहरण में दिखाया गया है, जब भी startResolutionForResult() को कॉल किया जाता है या GoogleApiAvailability.getErrorDialog() से डायलॉग दिखाया जाता है, तो आपके ऐप्लिकेशन को बूलियन true पर सेट करना चाहिए. इसके बाद, जब आपके ऐप्लिकेशन को onActivityResult() कॉलबैक में RESULT_OK मिले, तो बूलियन को 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 से मैन्युअल तरीके से कनेक्ट करने के लिए तैयार हैं.