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

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

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

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

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

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

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

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

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

        // ...
    }
}

गतिविधि कॉल onStart() के बाद, आपका GoogleApiClient इंस्टेंस अपने-आप कनेक्ट हो जाएगा और onStop() को कॉल करने के बाद डिसकनेक्ट हो जाएगा. आपका ऐप्लिकेशन, कनेक्शन पूरा होने का इंतज़ार किए बिना, GoogleApiClient बनाने के तुरंत बाद, Google API के लिए रीड रिक्वेस्ट बनाना शुरू कर सकता है.

Google की सेवाओं का इस्तेमाल करें

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

ध्यान दें: Google की खास सेवाओं पर कॉल करने से पहले, आपको सबसे पहले Google कंसोल में अपना ऐप्लिकेशन रजिस्टर करना होगा. निर्देशों के लिए, इस्तेमाल किए जा रहे एपीआई के लिए शुरुआती निर्देश वाली गाइड देखें. जैसे कि 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, हैंडहेल्ड और पहने जाने वाले डिवाइसों पर काम करने वाले ऐप्लिकेशन के लिए कम्यूनिकेशन चैनल की सुविधा देता है. इस एपीआई में डेटा ऑब्जेक्ट का एक सेट होता है, जिसे सिस्टम भेज और सिंक कर सकता है. साथ ही, इसमें ऐसे लोग होते हैं जो डेटा लेयर का इस्तेमाल करके आपके ऐप्लिकेशन को ज़रूरी इवेंट की सूचना देते हैं. Wearable API का इस्तेमाल, Android 4.3 (एपीआई लेवल 18) या इसके बाद के वर्शन वाले डिवाइसों पर तब किया जा सकता है, जब डिवाइस को कनेक्ट किया गया हो और Wear OS साथी ऐप्लिकेशन को इंस्टॉल किया गया हो.

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

अगर आपके ऐप्लिकेशन में Google के अन्य एपीआई के बजाय, 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 के अन्य एपीआई के साथ 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 से कनेक्ट किए बिना, 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() तरीके अपने-आप कॉल हो जाते हैं.

अगर Google Drive या Google Play Games जैसे ऐसे एपीआई से कनेक्ट करने के लिए GoogleApiClient का इस्तेमाल किया जा रहा है जिनकी पुष्टि करना ज़रूरी है, तो हो सकता है कि आपका पहला कनेक्शन काम न कर पाए. साथ ही, आपके ऐप्लिकेशन को 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 से मैन्युअल तरीके से कनेक्ट करने के लिए तैयार हैं.