การเข้าถึง Google APIs ด้วย GoogleApiClient (เลิกใช้งานแล้ว)

คุณใช้ออบเจ็กต์ GoogleApiClient ("ไคลเอ็นต์ Google API") เพื่อเข้าถึง Google API ที่มีให้ในไลบรารีบริการ Google Play ได้ (เช่น Google Sign-In, เกม และไดรฟ์) ไคลเอ็นต์ Google API ให้จุดแรกเข้าทั่วไปไปยังบริการ Google Play และจัดการการเชื่อมต่อเครือข่ายระหว่างอุปกรณ์ของผู้ใช้กับบริการ Google แต่ละอย่าง

อย่างไรก็ตาม อินเทอร์เฟซแบบใหม่และการติดตั้งใช้งานของ GoogleApi นั้นใช้งานง่ายกว่าและเป็นวิธีที่แนะนำในการเข้าถึง API ของบริการ Google Play โปรดดูการเข้าถึง Google API

คู่มือนี้แสดงวิธีทำสิ่งต่อไปนี้

  • จัดการการเชื่อมต่อกับบริการ Google Play โดยอัตโนมัติ
  • เรียกใช้ API แบบพร้อมกันและไม่พร้อมกันไปยังบริการ Google Play บริการใดก็ได้
  • จัดการการเชื่อมต่อกับบริการ Google Play ด้วยตนเองในกรณีที่จำเป็นต้องใช้ ดูข้อมูลเพิ่มเติมได้ที่การเชื่อมต่อที่จัดการด้วยตนเอง
รูปที่ 1: ภาพประกอบแสดงวิธีที่ไคลเอ็นต์ Google API มอบอินเทอร์เฟซสำหรับเชื่อมต่อและโทรออกไปยังบริการ Google Play ที่มีให้บริการ เช่น Google Play Games และ Google ไดรฟ์

ในการเริ่มต้นใช้งาน คุณต้องติดตั้งไลบรารีบริการ Google Play (เวอร์ชัน 15 ขึ้นไป) สำหรับ Android SDK ก่อน หากยังไม่ได้ดำเนินการ ให้ทำตามวิธีการในตั้งค่า SDK บริการ Google Play

เริ่มการเชื่อมต่อที่มีการจัดการโดยอัตโนมัติ

หลังจากลิงก์โปรเจ็กต์กับไลบรารีบริการ Google Play แล้ว ให้สร้างอินสแตนซ์ของ GoogleApiClient โดยใช้ GoogleApiClient.Builder API ในเมธอด onCreate() ของกิจกรรม คลาส GoogleApiClient.Builder มีเมธอดที่ให้คุณระบุ Google API ที่ต้องการใช้และขอบเขต OAuth 2.0 ที่ต้องการ ต่อไปนี้คือตัวอย่างโค้ดที่สร้างอินสแตนซ์ GoogleApiClient ที่เชื่อมต่อกับบริการ Google ไดรฟ์

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

คุณเพิ่ม API หลายรายการและหลายขอบเขตลงในไฟล์เดียวกันได้ GoogleApiClient โดยเพิ่มการเรียกเพิ่มเติมต่อท้าย addApi() และ addScope()

สำคัญ: หากกำลังเพิ่ม Wearable API ร่วมกับ API อื่นๆ ใน GoogleApiClient คุณอาจพบข้อผิดพลาดในการเชื่อมต่อไคลเอ็นต์ในอุปกรณ์ที่ไม่ได้ติดตั้งแอป Wear OS หากต้องการหลีกเลี่ยงข้อผิดพลาดในการเชื่อมต่อ ให้เรียกใช้เมธอด addApiIfAvailable() แล้วส่งผ่าน Wearable API เพื่อให้ลูกค้าสามารถจัดการ API ที่ขาดหายไปได้อย่างราบรื่น ดูข้อมูลเพิ่มเติมได้ที่เข้าถึง Wearable API

หากต้องการเริ่มการเชื่อมต่อที่มีการจัดการโดยอัตโนมัติ คุณต้องระบุการใช้งานสำหรับอินเทอร์เฟซ OnConnectionFailedListener เพื่อรับข้อผิดพลาดในการเชื่อมต่อที่แก้ไขไม่ได้ เมื่ออินสแตนซ์ GoogleApiClient ที่มีการจัดการอัตโนมัติพยายามเชื่อมต่อกับ Google API อินสแตนซ์จะแสดง UI โดยอัตโนมัติเพื่อพยายามแก้ไขความล้มเหลวในการเชื่อมต่อที่แก้ไขได้ (เช่น หากต้องอัปเดตบริการ Google Play) หากเกิดข้อผิดพลาดที่ไม่สามารถแก้ไขได้ คุณจะได้รับการติดต่อไปที่ onConnectionFailed()

คุณสามารถระบุการใช้งานที่ไม่บังคับสำหรับอินเทอร์เฟซ ConnectionCallbacks ได้ด้วยหากแอปต้องการทราบเมื่อมีการสร้างหรือระงับการเชื่อมต่อที่มีการจัดการโดยอัตโนมัติ เช่น หากแอปเรียกใช้การเขียนข้อมูลไปยัง Google API ระบบจะเรียกใช้เมธอดเหล่านี้หลังจากเรียกใช้เมธอด onConnected() แล้วเท่านั้น

ต่อไปนี้คือกิจกรรมตัวอย่างที่ใช้อินเทอร์เฟซ Callback และเพิ่มลงในไคลเอ็นต์ 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 ไดรฟ์หรือ Google Sign-In

เมื่อคุณส่งคำขออ่านหรือเขียนโดยใช้ GoogleApiClient ไคลเอ็นต์ API จะส่งกลับออบเจ็กต์ PendingResult ที่แสดงถึงคำขอ กรณีนี้จะเกิดขึ้นทันที ก่อนที่ระบบจะส่งคำขอไปยังบริการของ Google ที่แอปของคุณเรียกใช้

ตัวอย่างเช่น ต่อไปนี้คือคำขออ่านไฟล์จาก Google ไดรฟ์ที่มีออบเจ็กต์ PendingResult

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

หลังจากที่แอปมีออบเจ็กต์ PendingResult แล้ว แอปจะระบุได้ว่าจะจัดการคำขอเป็นการเรียกแบบไม่พร้อมกันหรือการเรียกพร้อมกัน

เคล็ดลับ: แอปของคุณสามารถจัดคิวคำขออ่านขณะที่ไม่ได้เชื่อมต่อกับบริการ Google Play เช่น แอปเรียกใช้เมธอดเพื่ออ่านไฟล์จาก Google ไดรฟ์ได้ ไม่ว่าอินสแตนซ์ GoogleApiClient จะเชื่อมต่อหรือไม่ก็ตาม หลังจากสร้างการเชื่อมต่อแล้ว ระบบจะดำเนินการกับคำขออ่านที่จัดคิวไว้ คำขอเขียนจะสร้างข้อผิดพลาดหากแอปของคุณเรียกใช้ บริการ Google Play เขียนเมธอดขณะที่ไคลเอ็นต์ 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 ใน Callback onResult() ระบบจะส่งออบเจ็กต์นั้นเป็นอินสแตนซ์ของคลาสย่อยที่เหมาะสมตามที่ระบุโดย API ที่คุณใช้อยู่ เช่น DriveApi.MetadataBufferResult

การใช้การโทรพร้อมกัน

หากต้องการให้โค้ดทำงานตามลำดับที่กำหนดไว้อย่างเคร่งครัด อาจเป็นเพราะผลลัพธ์ของการเรียกรายการหนึ่งเป็นอาร์กิวเมนต์ที่จำเป็นต้องใช้await()PendingResult การดำเนินการนี้จะบล็อกเทรดและแสดงผลออบเจ็กต์ Result เมื่อคำขอเสร็จสมบูรณ์ ออบเจ็กต์นี้นำส่งเป็นอินสแตนซ์ของคลาสย่อยที่เหมาะสมตามที่ API ที่คุณใช้ระบุ เช่น DriveApi.MetadataBufferResult

เนื่องจากการเรียกใช้ await() จะบล็อก Thread จนกว่าผลลัพธ์จะมาถึง แอปของคุณจึงไม่ควรส่งคำขอแบบพร้อมกันไปยัง Google API ในเทรด UI แอปของคุณสามารถสร้างชุดข้อความใหม่โดยใช้ออบเจ็กต์ AsyncTask และใช้ชุดข้อความนั้นเพื่อสร้างคำขอแบบซิงโครนัส

ตัวอย่างต่อไปนี้แสดงวิธีส่งคำขอไฟล์ไปยัง Google ไดรฟ์เป็นการเรียกพร้อมกัน

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 ซึ่งไม่ใช่ API อื่นๆ ของ Google คุณจะเพิ่ม 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
    }
    // ...
}

การใช้ Wearable API กับ Google API อื่นๆ

หากแอปใช้ 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 ไดรฟ์ได้โดยไม่ต้องเชื่อมต่อกับ Wearable API หากไม่พร้อมใช้งาน หลังจากที่คุณเชื่อมต่ออินสแตนซ์ GoogleApiClient แล้ว ให้ตรวจสอบว่า Wearable API พร้อมใช้งานก่อนเรียก API โดยทำดังนี้

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

การละเว้นความล้มเหลวในการเชื่อมต่อ API

หากคุณเรียกใช้ addApi() และ GoogleApiClient เชื่อมต่อกับ API ดังกล่าวไม่สำเร็จ การเชื่อมต่อทั้งหมดสำหรับไคลเอ็นต์นั้นจะล้มเหลวและทำให้เกิดการเรียกกลับ onConnectionFailed()

คุณสามารถลงทะเบียนความล้มเหลวในการเชื่อมต่อ API ที่จะถูกเพิกเฉยได้โดยใช้ addApiIfAvailable() หาก API ที่เพิ่มด้วย addApiIfAvailable() เชื่อมต่อไม่สำเร็จเนื่องจากเกิดข้อผิดพลาดที่กู้คืนไม่ได้ (เช่น API_UNAVAILABLE สำหรับ Wear) API นั้นถูกตัดออกจาก GoogleApiClient และไคลเอ็นต์จะเชื่อมต่อกับ API อื่นๆ แต่หากการเชื่อมต่อ API ไม่สำเร็จโดยมีข้อผิดพลาดที่กู้คืนได้ (เช่น ความตั้งใจในการแก้ปัญหาความยินยอม OAuth) การเชื่อมต่อไคลเอ็นต์จะไม่สำเร็จ เมื่อใช้การเชื่อมต่อที่มีการจัดการโดยอัตโนมัติ GoogleApiClient จะพยายามแก้ไขข้อผิดพลาดดังกล่าวเมื่อทำได้ เมื่อใช้การเชื่อมต่อที่จัดการด้วยตนเอง ระบบจะส่ง ConnectionResult ที่มีความตั้งใจในการแก้ปัญหาไปยัง Callback onConnectionFailed() ระบบจะไม่สนใจความล้มเหลวในการเชื่อมต่อ API เฉพาะในกรณีที่ไม่มีวิธีแก้ปัญหาสำหรับความล้มเหลวและมีการเพิ่ม API ด้วย addApiIfAvailable() ดูวิธีใช้การจัดการการเชื่อมต่อด้วยตนเองที่ไม่สำเร็จได้ที่จัดการความล้มเหลวในการเชื่อมต่อ

เนื่องจาก API ที่เพิ่มด้วย addApiIfAvailable() อาจไม่แสดงในอินสแตนซ์ GoogleApiClient ที่เชื่อมต่อเสมอไป คุณจึงควรปกป้องการเรียกใช้ API เหล่านี้โดยการเพิ่มการตรวจสอบโดยใช้ hasConnectedApi() หากต้องการดูสาเหตุที่ API บางรายการเชื่อมต่อไม่สำเร็จเมื่อไคลเอ็นต์เชื่อมต่อสำเร็จ ให้เรียกใช้ getConnectionResult() และรับรหัสข้อผิดพลาดจากออบเจ็กต์ ConnectionResult หากไคลเอ็นต์เรียกใช้ API ในขณะที่ไม่ได้เชื่อมต่อกับไคลเอ็นต์ การเรียกใช้จะไม่สำเร็จโดยมีรหัสสถานะ API_NOT_AVAILABLE

หาก API ที่จะเพิ่มผ่าน addApiIfAvailable() ต้องใช้ขอบเขตอย่างน้อย 1 รายการ ให้เพิ่มขอบเขตเหล่านั้นเป็นพารามิเตอร์ในการเรียกใช้เมธอด addApiIfAvailable() แทนการใช้เมธอด addScope() ระบบอาจไม่ขอขอบเขตที่เพิ่มโดยใช้แนวทางนี้หากเชื่อมต่อ API ไม่สำเร็จก่อนที่จะขอความยินยอม OAuth ขณะที่ขอบเขตที่เพิ่มด้วย addScope() จะได้รับการขอเสมอ

การเชื่อมต่อที่จัดการด้วยตนเอง

เนื้อหาส่วนใหญ่ของคู่มือนี้จะแสดงวิธีใช้ enableAutoManage เพื่อเริ่มการเชื่อมต่อที่มีการจัดการโดยอัตโนมัติพร้อมแก้ไขข้อผิดพลาดโดยอัตโนมัติ ในเกือบทุกกรณี วิธีนี้เป็นวิธีที่ดีและง่ายที่สุดในการเชื่อมต่อกับ Google APIs จากแอป Android อย่างไรก็ตาม มีบางสถานการณ์ที่คุณต้องการใช้การเชื่อมต่อที่จัดการด้วยตนเองกับ Google API ในแอป

  • เพื่อเข้าถึง Google API ภายนอกกิจกรรมหรือรักษาการควบคุมการเชื่อมต่อ API
  • เพื่อปรับแต่งการจัดการและแก้ปัญหาข้อผิดพลาดในการเชื่อมต่อ

ส่วนนี้จะแสดงตัวอย่าง Use Case เหล่านี้และขั้นสูงอื่นๆ

เริ่มการเชื่อมต่อที่มีการจัดการด้วยตนเอง

หากต้องการเริ่มการเชื่อมต่อที่มีการจัดการด้วยตนเองกับ GoogleApiClient คุณต้องระบุการใช้งานสำหรับอินเทอร์เฟซ Callback ConnectionCallbacks และ OnConnectionFailedListener อินเทอร์เฟซเหล่านี้จะได้รับ Callback เพื่อตอบสนองเมธอด connect() แบบไม่พร้อมกันเมื่อการเชื่อมต่อกับบริการ Google Play สำเร็จ ไม่สำเร็จ หรือถูกระงับ

    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 ไดรฟ์หรือ Google Play Games ก็มีโอกาสสูงที่การเชื่อมต่อครั้งแรกของคุณจะล้มเหลวและแอปจะได้รับการเรียก onConnectionFailed() พร้อมข้อผิดพลาด SIGN_IN_REQUIRED เนื่องจากไม่ได้ระบุบัญชีผู้ใช้

จัดการความล้มเหลวในการเชื่อมต่อ

เมื่อแอปได้รับการเรียกไปยัง onConnectionFailed() การเรียกกลับ คุณควรเรียกใช้ hasResolution() ในออบเจ็กต์ ConnectionResult ที่มีให้ หากผลลัพธ์เป็น "จริง" แอปสามารถขอให้ผู้ใช้ดำเนินการแก้ไขข้อผิดพลาดโดยทันทีด้วยการเรียก startResolutionForResult() ในออบเจ็กต์ ConnectionResult ในกรณีนี้ เมธอด startResolutionForResult() จะทำงานเหมือนกับ startActivityForResult() และเปิดกิจกรรมที่เหมาะกับบริบทซึ่งช่วยให้ผู้ใช้แก้ไขข้อผิดพลาดได้ (เช่น กิจกรรมที่ช่วยให้ผู้ใช้เลือกบัญชี)

หาก hasResolution() แสดงผลเป็น "เท็จ" แอปของคุณควรเรียกใช้ GoogleApiAvailability.getErrorDialog() โดยส่งรหัสข้อผิดพลาดไปยังเมธอดนี้ การดำเนินการนี้จะแสดง Dialog จากบริการ Google Play ซึ่งเหมาะสำหรับข้อผิดพลาด กล่องโต้ตอบอาจมีข้อความอธิบายข้อผิดพลาดหรือยังอาจให้การดำเนินการเพื่อเปิดกิจกรรมที่สามารถแก้ไขข้อผิดพลาดได้ (เช่น เมื่อผู้ใช้ต้องติดตั้งบริการ Google Play เวอร์ชันใหม่)

ตัวอย่างเช่น ตอนนี้เมธอด Callback 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() พร้อมรหัสผลลัพธ์ 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 ด้วยตนเองแล้ว