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

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

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

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

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

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

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

जब आपका प्रोजेक्ट, Google Play services की लाइब्रेरी से लिंक हो जाएगा, तो अपनी गतिविधि के तरीके onCreate() में GoogleApiClient.Builder एपीआई का इस्तेमाल करके GoogleApiClient का इंस्टेंस बनाएं. GoogleApiClient.Builder क्लास में ऐसे तरीके उपलब्ध होते हैं जिनकी मदद से, अपनी पसंद के मुताबिक Google API और 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();

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

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

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

अनुरोध को एसिंक्रोनस करने के लिए, 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.
            // ...
        }
    });
}

जब आपके ऐप्लिकेशन को 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 का स्टैंड-अलोन इस्तेमाल करना

अगर आपका ऐप्लिकेशन Wearable API का इस्तेमाल करता है, लेकिन अन्य Google 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
    }
    // ...
}

Wearable API को अन्य Google 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);

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 सेवाओं का कनेक्शन सफल होने, फ़ेल होने या निलंबित होने पर, इन इंटरफ़ेस को एसिंक्रोनस connect() तरीके के रिस्पॉन्स में कॉलबैक मिलते हैं.

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

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

जब आपके ऐप्लिकेशन को 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 सेवाओं से मैन्युअल रूप से कनेक्ट करने के लिए तैयार हैं.