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

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

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

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

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

เนื่องจากการเรียกใช้ await() จะบล็อกชุดข้อความจนกว่าผลลัพธ์จะมาถึง แอปของคุณจึงไม่ควรส่งคำขอพร้อมกันไปยัง Google APIs ในชุดข้อความ 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
        // ...
    }
}

เข้าถึง Wearable API

Wearable API เป็นช่องทางการสื่อสารสำหรับแอปที่ทำงานในอุปกรณ์พกพาและอุปกรณ์ที่สวมใส่ได้ API ประกอบด้วยชุดออบเจ็กต์ข้อมูลที่ระบบส่งและซิงค์ข้อมูลได้ และผู้ฟังที่แจ้งเตือนแอปของคุณเกี่ยวกับเหตุการณ์สำคัญโดยใช้ชั้นข้อมูล Wearable API พร้อมใช้งานในอุปกรณ์ที่ใช้ Android 4.3 (API ระดับ 18) ขึ้นไป เมื่อมีการเชื่อมต่ออุปกรณ์ที่สวมใส่ได้และมีแอปที่ใช้ร่วมกับ Wear OS ติดตั้งอยู่ในอุปกรณ์

การใช้ API อุปกรณ์ที่สวมใส่ได้แบบสแตนด์อโลน

หากแอปใช้ Wearable API แต่ไม่ได้ใช้ Google API อื่นๆ คุณสามารถเพิ่ม 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 กับ API อื่นๆ ของ Google

หากแอปใช้ Wearable API นอกเหนือจาก Google API อื่นๆ ให้เรียกใช้เมธอด 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 ที่มี Intent ในการแก้ไขปัญหาไปยังโค้ดเรียกกลับ 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 APIs ในแอป

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

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

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

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

เช่น ตอนนี้วิธีการเรียกกลับ 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 ด้วยตนเองอย่างปลอดภัยแล้ว