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

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

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

คู่มือนี้จะแสดงวิธีดำเนินการต่อไปนี้

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

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

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

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

การใช้การเรียกแบบซิงค์

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

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

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

private void loadFile(String filename) {
    new GetFileTask().execute(filename);
}

private class GetFileTask extends AsyncTask<String, Void, Void> {
    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 ประกอบด้วยชุดออบเจ็กต์ข้อมูลซึ่งระบบสามารถส่งและซิงค์ รวมถึง Listener ที่แจ้งเตือนแอปเกี่ยวกับเหตุการณ์สําคัญโดยใช้เลเยอร์ข้อมูล Wearable API พร้อมใช้งานในอุปกรณ์ที่ใช้ Android 4.3 (API ระดับ 18) ขึ้นไปเมื่อเชื่อมต่ออุปกรณ์ที่สวมใส่ได้และติดตั้งแอปที่ใช้ร่วมกันของ Wear OS ในอุปกรณ์แล้ว

การใช้ Wearable 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 กับ Google APIs อื่นๆ

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

จัดการการเชื่อมต่อที่ไม่สําเร็จ

เมื่อแอปได้รับการเรียกใช้ Callback ของ onConnectionFailed() คุณควรเรียกใช้ hasResolution() ในออบเจ็กต์ ConnectionResult ที่ระบุ หากผลลัพธ์เป็น True แอปจะขอให้ผู้ใช้ดำเนินการทันทีเพื่อแก้ไขข้อผิดพลาดได้โดยเรียกใช้ 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() แล้ว กิจกรรมของคุณจะได้รับการเรียกกลับพร้อมรหัสผลลัพธ์ RESULT_OKonActivityResult() จากนั้นแอปจะเรียกใช้ 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() อีกครั้ง ซึ่งจะสร้างกล่องโต้ตอบเครื่องมือเลือกบัญชีอีกกล่องหนึ่งต่อจากกล่องโต้ตอบที่มีอยู่

Bool นี้จะทํางานตามวัตถุประสงค์ก็ต่อเมื่อค่านี้ยังคงอยู่ตลอดอินสแตนซ์ของกิจกรรม ส่วนถัดไปจะอธิบายวิธีรักษาสถานะการจัดการข้อผิดพลาดของแอปไว้ แม้ว่าผู้ใช้จะดำเนินการอื่นๆ หรือเกิดเหตุการณ์อื่นๆ ในอุปกรณ์

รักษาสถานะขณะแก้ไขข้อผิดพลาด

คุณต้องเก็บค่าบูลีนไว้เพื่อติดตามว่าแอปพยายามแก้ไขข้อผิดพลาดอยู่หรือไม่ เพื่อหลีกเลี่ยงการเรียกใช้โค้ดใน onConnectionFailed() ขณะที่การพยายามแก้ไขข้อผิดพลาดก่อนหน้านี้กำลังดำเนินอยู่

ดังที่แสดงในตัวอย่างโค้ดด้านบน แอปควรตั้งค่าบูลีนเป็น true ทุกครั้งที่เรียกใช้ startResolutionForResult() หรือแสดงกล่องโต้ตอบจาก GoogleApiAvailability.getErrorDialog() จากนั้นเมื่อแอปได้รับ RESULT_OK ใน Callback ของ 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 ด้วยตนเองแล้ว