ภาพรวมของบริการขอบเขต

บริการที่มีผลผูกพันคือเซิร์ฟเวอร์ในอินเทอร์เฟซแบบไคลเอ็นต์-เซิร์ฟเวอร์ ทำให้คอมโพเนนต์ เช่น กิจกรรมที่เชื่อมโยงกับบริการ ส่งคำขอ รับการตอบกลับ และดำเนินการ การสื่อสารระหว่างโปรเซส (IPC) บริการที่มีขอบเขตมักทํางานอยู่ขณะที่ให้บริการอื่นเท่านั้น คอมโพเนนต์ของแอปพลิเคชันและจะไม่ทำงานในเบื้องหลังอย่างไม่มีกำหนด

เอกสารนี้อธิบายวิธีสร้างบริการที่เชื่อมโยงกับการเชื่อมโยง รวมถึงวิธีเชื่อมโยง ไปที่บริการจากคอมโพเนนต์อื่นๆ ของแอปพลิเคชัน สำหรับข้อมูลเพิ่มเติมเกี่ยวกับบริการใน เช่น วิธีส่งการแจ้งเตือนจากบริการและตั้งค่าให้เรียกใช้บริการ อยู่ด้านหน้า ให้ดูที่ ภาพรวมของบริการ

ข้อมูลเบื้องต้น

บริการที่มีผลผูกพันคือการติดตั้งใช้งานคลาส Service ที่อนุญาตให้ จะเชื่อมโยงและโต้ตอบกับแอปพลิเคชันอื่น ในการให้การเชื่อมโยงสำหรับ แสดงว่าคุณใช้เมธอด Callback onBind() ช่วงเวลานี้ จะแสดงผลออบเจ็กต์ IBinder ที่กำหนดอินเทอร์เฟซการเขียนโปรแกรมที่ ของลูกค้าจะใช้เพื่อโต้ตอบกับบริการได้

เชื่อมโยงกับบริการที่เริ่มต้น

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

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

แม้ว่าโดยปกติแล้วคุณจะใช้ onBind() อย่างใดอย่างหนึ่ง หรือ onStartCommand() บางครั้ง เพื่อ นำมาใช้ทั้ง 2 อย่าง ตัวอย่างเช่น โปรแกรมเล่นเพลงอาจพบว่ามีประโยชน์ที่จะปล่อยให้บริการทำงานได้ ไปตลอดกาล ทั้งยังทำให้เกิดการผูกมัด วิธีนี้จะทำให้กิจกรรมสามารถเริ่มบริการเพื่อเล่น และเพลงจะเล่นต่อไปแม้ว่าผู้ใช้จะออกจากแอปพลิเคชัน จากนั้น เมื่อผู้ใช้ กลับไปที่แอปพลิเคชัน กิจกรรมสามารถเชื่อมโยงกับบริการเพื่อให้สามารถควบคุม การเล่น

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวงจรของบริการเมื่อเพิ่มการเชื่อมโยงกับบริการที่เริ่มต้น โปรดดูส่วนจัดการวงจรของบริการที่มีผลผูกพัน

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

วันและเวลา ระบบ Android สร้างการเชื่อมต่อระหว่างไคลเอ็นต์และบริการ โทรหา onServiceConnected() ในวันที่ ServiceConnection เมธอด onServiceConnected() มี IBinder ซึ่งไคลเอ็นต์จะใช้เพื่อสื่อสารกับบริการที่เชื่อมโยง

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

เมื่อไคลเอ็นต์สุดท้ายยกเลิกการเชื่อมโยงกับบริการ ระบบจะทำลายบริการ เว้นแต่ บริการ เริ่มต้นโดยใช้ startService()

ส่วนที่สำคัญที่สุดของการติดตั้งใช้งานบริการที่มีผลผูกพันคือการกำหนดอินเทอร์เฟซ ที่เมธอด Callback ของ onBind() แสดงผล ดังต่อไปนี้ ส่วนจะอธิบายถึงวิธีการต่างๆ ที่คุณสามารถกำหนด อินเทอร์เฟซของ IBinder

สร้างบริการที่มีผลผูกพัน

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

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

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

ใช้ Messenger
หากคุณต้องการให้อินเทอร์เฟซทำงานในกระบวนการต่างๆ คุณสามารถสร้าง อินเทอร์เฟซสำหรับบริการที่มี Messenger ในกรณีนี้ บริการ กำหนด Handler ที่ตอบสนองต่อวัตถุ Message ประเภทต่างๆ

Handlerเครื่องนี้ เป็นพื้นฐานของ Messenger ที่แชร์ IBinder กับไคลเอ็นต์ โดยให้ไคลเอ็นต์ส่งคำสั่งไปยังบริการโดยใช้ออบเจ็กต์ Message นอกจากนี้ ไคลเอ็นต์ยังสามารถกำหนด Messenger ของ เพื่อที่บริการจะสามารถส่งข้อความกลับได้

วิธีนี้เป็นวิธีที่ง่ายที่สุดในการดำเนินการสื่อสารระหว่างโปรเซส (IPC) เนื่องจาก Messenger จัดคิวคำขอทั้งหมดไว้ในเทรดเดียว คุณจึงไม่ต้องออกแบบ เพื่อให้บริการของคุณปลอดภัยด้วยชุดข้อความ

ใช้ AIDL
Android Interface Definition Language (AIDL) จะแยกย่อยวัตถุต่างๆ พื้นฐานที่ระบบปฏิบัติการสามารถเข้าใจและเจาะลึกกระบวนการต่างๆ เพื่อดำเนินการ IPC เทคนิคก่อนหน้านี้ที่ใช้ Messenger จะใช้ AIDL ตามที่แสดง โครงสร้างสำคัญ

ดังที่กล่าวไว้ในส่วนก่อนหน้านี้ Messenger สร้างคิวของ คำขอของไคลเอ็นต์ทั้งหมดในเทรดเดียว ดังนั้นบริการจะได้รับคำขอทีละรายการ หาก อย่างไรก็ตาม หากต้องการให้บริการจัดการคำขอหลายรายการพร้อมกัน คุณจะใช้ AIDL ได้ โดยตรง ในกรณีนี้ บริการของคุณต้องปลอดภัยเทรดและใช้มัลติเธรดได้

หากต้องการใช้ AIDL โดยตรง สร้างไฟล์ .aidl ที่กำหนดอินเทอร์เฟซการเขียนโปรแกรม เครื่องมือ Android SDK ใช้ ไฟล์นี้เพื่อสร้างคลาสนามธรรมที่นำอินเทอร์เฟซและจัดการ IPC ซึ่งคุณ สามารถขยายภายในบริการของคุณ

หมายเหตุ: สำหรับแอปพลิเคชันส่วนใหญ่ AIDL ไม่ใช่ตัวเลือกที่ดีที่สุด สร้างบริการที่เชื่อมโยงไว้ เนื่องจากอาจต้องใช้ความสามารถในการจัดการชุดข้อความหลายรายการและ อาจส่งผลให้การใช้งานซับซ้อนขึ้น ดังนั้น เอกสารฉบับนี้ไม่ได้กล่าวถึงวิธี เพื่อใช้กับบริการของคุณ หากคุณแน่ใจว่าต้องการ หากต้องการใช้ AIDL โดยตรง โปรดดู AIDL เอกสาร

ขยายคลาส Binder

หากมีเฉพาะแอปพลิเคชันในเครื่องที่ใช้บริการของคุณ และไม่ต้อง ทำงานข้ามกระบวนการ ก็สามารถใช้คลาส Binder ของคุณเองที่ให้ลูกค้าเข้าถึง เข้าถึงวิธีการสาธารณะในบริการ

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

วิธีตั้งค่ามีดังนี้

  1. ในบริการ ให้สร้างอินสแตนซ์ของ Binder ที่ ดำเนินการอย่างใดอย่างหนึ่งต่อไปนี้
    • มีวิธีสาธารณะที่ไคลเอ็นต์สามารถเรียกใช้ได้
    • แสดงผลอินสแตนซ์ Service ปัจจุบัน ซึ่งมีเมธอดสาธารณะ ที่ลูกค้าสามารถโทรได้
    • แสดงผลอินสแตนซ์ของคลาสอื่นที่โฮสต์โดยบริการพร้อมเมธอดสาธารณะ ที่ลูกค้าสามารถโทรได้
  2. แสดงผลอินสแตนซ์นี้ของ Binder จากเมธอด Callback onBind()
  3. ในไคลเอ็นต์ ให้รับ Binder จากเมธอด Callback onServiceConnected() และ เรียกใช้บริการที่เกี่ยวข้องโดยใช้วิธีการที่ให้ไว้

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

ตัวอย่างเช่น นี่คือบริการที่ให้ลูกค้าสามารถเข้าถึงเมธอดในบริการผ่าน การใช้งาน Binder:

Kotlin

class LocalService : Service() {
    // Binder given to clients.
    private val binder = LocalBinder()

    // Random number generator.
    private val mGenerator = Random()

    /** Method for clients.  */
    val randomNumber: Int
        get() = mGenerator.nextInt(100)

    /**
     * Class used for the client Binder. Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    inner class LocalBinder : Binder() {
        // Return this instance of LocalService so clients can call public methods.
        fun getService(): LocalService = this@LocalService
    }

    override fun onBind(intent: Intent): IBinder {
        return binder
    }
}

Java

public class LocalService extends Service {
    // Binder given to clients.
    private final IBinder binder = new LocalBinder();
    // Random number generator.
    private final Random mGenerator = new Random();

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods.
            return LocalService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    /** Method for clients. */
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}

LocalBinder จะเตรียมเมธอด getService() ไว้ให้ไคลเอ็นต์เพื่อเรียกข้อมูล อินสแตนซ์ปัจจุบันของ LocalService ซึ่งจะช่วยให้ไคลเอ็นต์เรียกใช้เมธอดสาธารณะใน service. ตัวอย่างเช่น ลูกค้าจะโทรหา getRandomNumber() จากบริการได้

นี่คือกิจกรรมที่เชื่อมโยงกับ LocalService และการเรียกใช้ getRandomNumber() เมื่อมีการคลิกปุ่ม:

Kotlin

class BindingActivity : Activity() {
    private lateinit var mService: LocalService
    private var mBound: Boolean = false

    /** Defines callbacks for service binding, passed to bindService().  */
    private val connection = object : ServiceConnection {

        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance.
            val binder = service as LocalService.LocalBinder
            mService = binder.getService()
            mBound = true
        }

        override fun onServiceDisconnected(arg0: ComponentName) {
            mBound = false
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
    }

    override fun onStart() {
        super.onStart()
        // Bind to LocalService.
        Intent(this, LocalService::class.java).also { intent ->
            bindService(intent, connection, Context.BIND_AUTO_CREATE)
        }
    }

    override fun onStop() {
        super.onStop()
        unbindService(connection)
        mBound = false
    }

    /** Called when a button is clicked (the button in the layout file attaches to
     * this method with the android:onClick attribute).  */
    fun onButtonClick(v: View) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call is something that might hang, then put this request
            // in a separate thread to avoid slowing down the activity performance.
            val num: Int = mService.randomNumber
            Toast.makeText(this, "number: $num", Toast.LENGTH_SHORT).show()
        }
    }
}

Java

public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to LocalService.
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        unbindService(connection);
        mBound = false;
    }

    /** Called when a button is clicked (the button in the layout file attaches to
      * this method with the android:onClick attribute). */
    public void onButtonClick(View v) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call is something that might hang, then put this request
            // in a separate thread to avoid slowing down the activity performance.
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    /** Defines callbacks for service binding, passed to bindService(). */
    private ServiceConnection connection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance.
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
}

ตัวอย่างก่อนหน้านี้แสดงวิธีที่ไคลเอ็นต์เชื่อมโยงกับบริการโดยใช้การดำเนินการ ServiceConnection และการเรียกกลับ onServiceConnected() ถัดไป จะให้ข้อมูลเพิ่มเติมเกี่ยวกับขั้นตอนการเชื่อมโยงกับบริการ

หมายเหตุ: ในตัวอย่างก่อนหน้านี้ เมธอด onStop() จะยกเลิกการเชื่อมโยงไคลเอ็นต์จากบริการ ยกเลิกการผูกมัดลูกค้าจากบริการในเวลาที่เหมาะสม ตามที่กล่าวไว้ใน ส่วนหมายเหตุเพิ่มเติม

สำหรับโค้ดตัวอย่างเพิ่มเติม โปรดดู LocalService.javaและ LocalServiceActivities.java ใน ApiDemos

ใช้ Messenger

หากต้องการใช้บริการเพื่อสื่อสารกับกระบวนการระยะไกล คุณสามารถใช้ Messenger เพื่อมอบอินเทอร์เฟซสำหรับบริการของคุณ เทคนิคนี้ช่วยให้ คุณดำเนินการสื่อสารระหว่างโปรเซส (IPC) ได้โดยไม่ต้องใช้ AIDL

การใช้ Messenger สำหรับอินเทอร์เฟซของคุณคือ ง่ายกว่าการใช้ AIDL เนื่องจากคิวของ Messenger การโทรทั้งหมดไปยังบริการ อินเทอร์เฟซ AIDL เพียงอย่างเดียวจะส่งคำขอหลายรายการพร้อมกันไปยัง ซึ่งต้องจัดการกับมัลติเทรด

สำหรับแอปพลิเคชันส่วนใหญ่ บริการนี้ไม่จำเป็นต้องดำเนินการหลายๆ ชุดข้อความ ดังนั้นการใช้ Messenger จะช่วยให้บริการจัดการการเรียกใช้ได้ทีละ 1 สาย หากเป็นช่วงสำคัญ ว่าบริการของคุณเป็นแบบมัลติเธรด ให้ใช้ AIDL เพื่อกำหนดอินเทอร์เฟซของคุณ

สรุปวิธีใช้ Messenger มีดังนี้

  1. บริการใช้ Handler ที่ได้รับการติดต่อกลับสำหรับ สายจากลูกค้า
  2. บริการใช้ Handler เพื่อสร้าง Messenger ออบเจ็กต์ (ซึ่งเป็นการอ้างถึง Handler)
  3. Messenger สร้าง IBinder ที่บริการ ส่งคืนให้ลูกค้าจาก onBind()
  4. ลูกค้าใช้ IBinder เพื่อสร้าง Messenger (ซึ่งอ้างอิงถึง Handler ของบริการ) ซึ่งไคลเอ็นต์ใช้เพื่อส่ง Message ออบเจ็กต์ไปยังบริการ
  5. บริการจะได้รับ Message แต่ละรายการใน Handler โดยเฉพาะในเมธอด handleMessage()

จึงจะไม่มีวิธีการให้ลูกค้าเรียกใช้บริการ แต่ ไคลเอ็นต์ส่งข้อความ (Message ออบเจ็กต์) ที่บริการ รับใน Handler

ต่อไปนี้เป็นตัวอย่างบริการง่ายๆ ที่ใช้อินเทอร์เฟซ Messenger

Kotlin

/** Command to the service to display a message.  */
private const val MSG_SAY_HELLO = 1

class MessengerService : Service() {

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    private lateinit var mMessenger: Messenger

    /**
     * Handler of incoming messages from clients.
     */
    internal class IncomingHandler(
            context: Context,
            private val applicationContext: Context = context.applicationContext
    ) : Handler() {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                MSG_SAY_HELLO ->
                    Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show()
                else -> super.handleMessage(msg)
            }
        }
    }

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    override fun onBind(intent: Intent): IBinder? {
        Toast.makeText(applicationContext, "binding", Toast.LENGTH_SHORT).show()
        mMessenger = Messenger(IncomingHandler(this))
        return mMessenger.binder
    }
}

Java

public class MessengerService extends Service {
    /**
     * Command to the service to display a message.
     */
    static final int MSG_SAY_HELLO = 1;

    /**
     * Handler of incoming messages from clients.
     */
    static class IncomingHandler extends Handler {
        private Context applicationContext;

        IncomingHandler(Context context) {
            applicationContext = context.getApplicationContext();
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    Messenger mMessenger;

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        mMessenger = new Messenger(new IncomingHandler(this));
        return mMessenger.getBinder();
    }
}

เมธอด handleMessage() ใน Handler คือที่ที่บริการจะได้รับ Message ขาเข้า และตัดสินใจว่าจะทำอะไรโดยอิงตามสมาชิก what

สิ่งที่ไคลเอ็นต์ต้องทำคือสร้าง Messenger ตาม IBinder ที่บริการส่งคืนมา และส่งข้อความโดยใช้ send() เช่น นี่คือกิจกรรมที่เชื่อมโยงกับ และส่งข้อความ MSG_SAY_HELLO ไปยังบริการ:

Kotlin

class ActivityMessenger : Activity() {
    /** Messenger for communicating with the service.  */
    private var mService: Messenger? = null

    /** Flag indicating whether we have called bind on the service.  */
    private var bound: Boolean = false

    /**
     * Class for interacting with the main interface of the service.
     */
    private val mConnection = object : ServiceConnection {

        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = Messenger(service)
            bound = true
        }

        override fun onServiceDisconnected(className: ComponentName) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected—that is, its process crashed.
            mService = null
            bound = false
        }
    }

    fun sayHello(v: View) {
        if (!bound) return
        // Create and send a message to the service, using a supported 'what' value.
        val msg: Message = Message.obtain(null, MSG_SAY_HELLO, 0, 0)
        try {
            mService?.send(msg)
        } catch (e: RemoteException) {
            e.printStackTrace()
        }

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
    }

    override fun onStart() {
        super.onStart()
        // Bind to the service.
        Intent(this, MessengerService::class.java).also { intent ->
            bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
        }
    }

    override fun onStop() {
        super.onStop()
        // Unbind from the service.
        if (bound) {
            unbindService(mConnection)
            bound = false
        }
    }
}

Java

public class ActivityMessenger extends Activity {
    /** Messenger for communicating with the service. */
    Messenger mService = null;

    /** Flag indicating whether we have called bind on the service. */
    boolean bound;

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = new Messenger(service);
            bound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected—that is, its process crashed.
            mService = null;
            bound = false;
        }
    };

    public void sayHello(View v) {
        if (!bound) return;
        // Create and send a message to the service, using a supported 'what' value.
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to the service.
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service.
        if (bound) {
            unbindService(mConnection);
            bound = false;
        }
    }
}

ตัวอย่างนี้ไม่ได้แสดงให้เห็นว่าบริการจะตอบสนองลูกค้าได้อย่างไร หากคุณต้องการ ในการตอบสนอง คุณจะต้องสร้าง Messenger ในไคลเอ็นต์ด้วย เมื่อลูกค้าได้รับการติดต่อกลับจาก onServiceConnected() ระบบจะส่ง Message ไปยังบริการที่มี Messenger ของไคลเอ็นต์ในพารามิเตอร์ replyTo ของเมธอด send()

คุณสามารถดูตัวอย่างวิธีการรับส่งข้อความแบบ 2 ทางใน MessengerService.java (บริการ) และ MessengerServiceActivities.java (ไคลเอ็นต์) ตัวอย่าง

เชื่อมโยงกับบริการ

คอมโพเนนต์ของแอปพลิเคชัน (ไคลเอ็นต์) สามารถเชื่อมโยงกับบริการได้โดยการเรียกใช้ bindService() Android จากนั้นระบบจะเรียกเมธอด onBind() ของบริการ ซึ่งแสดงผล IBinder สำหรับการโต้ตอบกับ บริการ

การเชื่อมโยงจะเป็นแบบไม่พร้อมกัน และ bindService() จะแสดงผลทันทีโดยไม่ต้องแสดงผล IBinder เป็น ไคลเอ็นต์ หากต้องการรับ IBinder ลูกค้าจะต้องสร้าง อินสแตนซ์ของ ServiceConnection และส่งไปยัง bindService() ServiceConnection มีวิธี Callback ที่เมธอด เพื่อให้ระบบส่ง IBinder

หมายเหตุ: เฉพาะกิจกรรม บริการ และผู้ให้บริการเนื้อหาเท่านั้นที่สามารถเชื่อมโยงได้ บริการโดยไม่สามารถเชื่อมโยงกับบริการจาก Broadcast Receiver ได้

ในการเชื่อมโยงกับบริการจากลูกค้า ให้ทำตามขั้นตอนต่อไปนี้

  1. นำ ServiceConnection มาใช้

    การใช้งานของคุณต้องลบล้างเมธอด Callback 2 วิธีต่อไปนี้

    onServiceConnected()
    ระบบขอให้ส่ง IBinder ที่ส่งคืนโดย เมธอด onBind() ของบริการ
    onServiceDisconnected()
    ระบบ Android เรียกใช้เมื่อเชื่อมต่อกับบริการโดยไม่คาดคิด เช่น เมื่อบริการขัดข้องหรือหยุดทำงาน สิ่งที่ไม่ใช่ โดยเรียกเมื่อ การยกเลิกการเชื่อมโยงไคลเอ็นต์
  2. เรียกใช้ bindService() ผ่านการใช้งาน ServiceConnection

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

  3. เมื่อระบบเรียกใช้เมธอด Callback ของ onServiceConnected() คุณจะเริ่มโทรหาบริการได้โดยใช้ เมธอดที่กำหนดโดยอินเทอร์เฟซ
  4. หากต้องการยกเลิกการเชื่อมต่อกับบริการ โปรดโทรไปที่ unbindService()

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

ตัวอย่างต่อไปนี้เชื่อมต่อไคลเอ็นต์กับบริการที่สร้างโดย ขยายคลาส Binder ดังนั้นสิ่งที่คุณต้องทำก็คือการแคสต์ไฟล์ที่แสดงผล IBinder ไปยังคลาส LocalBinder และขออินสแตนซ์ LocalService:

Kotlin

var mService: LocalService

val mConnection = object : ServiceConnection {
    // Called when the connection with the service is established.
    override fun onServiceConnected(className: ComponentName, service: IBinder) {
        // Because we have bound to an explicit
        // service that is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        val binder = service as LocalService.LocalBinder
        mService = binder.getService()
        mBound = true
    }

    // Called when the connection with the service disconnects unexpectedly.
    override fun onServiceDisconnected(className: ComponentName) {
        Log.e(TAG, "onServiceDisconnected")
        mBound = false
    }
}

Java

LocalService mService;
private ServiceConnection mConnection = new ServiceConnection() {
    // Called when the connection with the service is established.
    public void onServiceConnected(ComponentName className, IBinder service) {
        // Because we have bound to an explicit
        // service that is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        LocalBinder binder = (LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }

    // Called when the connection with the service disconnects unexpectedly.
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "onServiceDisconnected");
        mBound = false;
    }
};

เมื่อใช้ ServiceConnection นี้ ไคลเอ็นต์จะผูกกับบริการได้ โดยส่ง ไปยัง bindService() ดังที่ปรากฏในตัวอย่างต่อไปนี้

Kotlin

Intent(this, LocalService::class.java).also { intent ->
    bindService(intent, connection, Context.BIND_AUTO_CREATE)
}

Java

Intent intent = new Intent(this, LocalService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
  • พารามิเตอร์แรกของ bindService() คือ Intent ที่ระบุชื่อบริการที่จะเชื่อมโยงอย่างชัดเจน

    ข้อควรระวัง: หากคุณใช้ Intent เพื่อเชื่อมโยงกับ คุณ Service ตรวจสอบว่าแอปปลอดภัยโดยใช้คำสั่งที่ชัดแจ้ง Intent การใช้ Intent แบบไม่เจาะจงปลายทางเพื่อเริ่มบริการเป็น เนื่องจากคุณไม่สามารถแน่ใจได้ว่าบริการใดตอบสนองต่อเจตนาของตน และผู้ใช้ไม่สามารถเห็นได้ว่าบริการใดเริ่มทำงานบ้าง เริ่มตั้งแต่ Android 5.0 (API ระดับ 21) ระบบ จะมีข้อยกเว้นหากคุณโทรหา bindService() โดยมีเจตนาโดยนัย

  • พารามิเตอร์ที่ 2 คือออบเจ็กต์ ServiceConnection
  • พารามิเตอร์ที่ 3 คือแฟล็กที่ระบุตัวเลือกในการเชื่อมโยง ซึ่งโดยทั่วไปจะเป็น BIND_AUTO_CREATE เพื่อสร้างบริการ หากยังไม่ได้ดำเนินการ ที่ยังมีชีวิต ค่าอื่นๆ ที่เป็นไปได้คือ BIND_DEBUG_UNBIND BIND_NOT_FOREGROUND หรือ 0 หากไม่มี

หมายเหตุเพิ่มเติม

หมายเหตุสําคัญเกี่ยวกับการเชื่อมโยงกับบริการมีดังนี้

  • ดักจับข้อยกเว้น DeadObjectException รายการเสมอ ซึ่งต้องมีการส่ง เมื่อการเชื่อมต่อขาดหาย ทั้งนี้ วิธีนี้เป็นข้อยกเว้นเพียงอย่างเดียวเท่านั้นที่ใช้โดยวิธีจากระยะไกล
  • ออบเจ็กต์มีการนับการอ้างอิงในกระบวนการต่างๆ
  • โดยปกติคุณจะจับคู่การเชื่อมโยงและยกเลิกการเชื่อมโยงในระหว่างการดำเนินการ การจับคู่ช่วงเวลาที่ปรากฏขึ้นและฉีกขาดในวงจรของลูกค้าตามที่อธิบายไว้ใน ตัวอย่างต่อไปนี้
    • หากต้องการโต้ตอบกับบริการขณะที่ระบบแสดงกิจกรรมเท่านั้น ให้เชื่อมโยงระหว่าง onStart() แล้วยกเลิกการเชื่อมโยงระหว่าง onStop()
    • หากคุณต้องการให้กิจกรรมได้รับการตอบกลับแม้ว่ากิจกรรมจะหยุดใน พื้นหลัง เชื่อมโยงระหว่าง onCreate() และยกเลิกการเชื่อมโยง ในช่วง onDestroy() โปรดระวังข้อความนี้เป็นนัยว่า จำเป็นต้องใช้บริการตลอดเวลาที่ทำงาน แม้แต่ในเบื้องหลัง ดังนั้นเมื่อ บริการอยู่ในอีกกระบวนการหนึ่ง แล้วคุณจะเพิ่มน้ำหนักของกระบวนการ ก็มีแนวโน้มที่จะถูกระบบเสียชีวิตมากกว่า

    หมายเหตุ: โดยปกติคุณไม่ได้เชื่อมโยงและเลิกเชื่อมโยง ในระหว่าง Callback onResume() และ onPause() ของกิจกรรม เนื่องจาก Callback เหล่านี้เกิดขึ้นทุก ของวงจร ลดการประมวลผลที่เกิดขึ้นในช่วงการเปลี่ยนเหล่านี้ให้น้อยที่สุด

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

สำหรับโค้ดตัวอย่างเพิ่มเติมที่แสดงวิธีเชื่อมโยงกับบริการ โปรดดู RemoteService.java ใน ApiDemos

จัดการวงจรของบริการที่เชื่อมโยงกับบริการ

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

อย่างไรก็ตาม หากคุณเลือกที่จะใช้เมธอด Callback onStartCommand() คุณจะต้องหยุดบริการอย่างชัดแจ้ง เนื่องจาก ถือว่าบริการเริ่มต้นแล้ว ในกรณีนี้ บริการจะทำงานจนถึงบริการ หยุดตัวเองโดยมี stopSelf() หรือคอมโพเนนต์อื่นเรียกใช้ stopService() ไม่ว่าจะผูกกับ ลูกค้า

นอกจากนี้ ถ้าบริการของคุณเริ่มต้นทำงานและยอมรับการเชื่อมโยง เมื่อระบบเรียก เมธอด onUnbind() ของคุณ คุณสามารถเลือกส่งคืน trueหากคุณต้องการรับสายไปยัง onRebind() ในครั้งถัดไปที่ลูกค้าผูกกับบริการ onRebind() ส่งคืนเป็นโมฆะ แต่ลูกค้ายังคงได้รับ IBinder ใน onServiceConnected() Callback ภาพต่อไปนี้แสดงตรรกะของวงจรชีวิตประเภทนี้

รูปที่ 1 วงจรสำหรับบริการที่เริ่มต้น และอนุญาตให้เชื่อมโยงด้วย

โปรดดูข้อมูลเพิ่มเติมเกี่ยวกับวงจรของบริการที่เริ่มต้นได้ที่ภาพรวมของบริการ