Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Ringkasan layanan terikat

Layanan terikat adalah server di antarmuka klien-server. Layanan terikat memungkinkan komponen-komponen (seperti aktivitas) untuk diikat ke layanan, mengirim permintaan, menerima respons, dan bahkan melakukan komunikasi antarproses (IPC). Layanan terikat biasanya aktif hanya saat melayani komponen aplikasi lain dan tidak berjalan di latar belakang terus-menerus.

Dokumen ini menampilkan cara membuat layanan terikat, termasuk cara mengikat ke layanan dari komponen aplikasi lain. Anda juga harus mengacu dokumen Layanan untuk informasi tambahan tentang layanan secara umum, seperti cara menyampaikan notifikasi dari layanan, mengatur layanan agar berjalan di latar depan, dan lain-lain.

Dasar-dasar

Layanan terikat adalah implementasi class Service yang memungkinkan aplikasi lain diikat padanya dan berinteraksi dengannya. Untuk menyediakan pengikatan bagi sebuah layanan, Anda harus mengimplementasikan metode callback onBind(). Metode ini mengembalikan objek IBinder yang mendefinisikan antarmuka pemrograman yang bisa digunakan klien untuk berinteraksi dengan layanan.

Mengikat ke layanan yang sudah dimulai

Seperti dibahas dalam dokumen Layanan, Anda bisa membuat layanan yang dimulai sekaligus diikat. Yakni, layanan bisa dimulai dengan memanggil startService(), yang memungkinkan layanan berjalan terus-menerus, dan juga memungkinkan klien mengikat ke layanan dengan memanggil bindService().

Jika Anda mengizinkan layanan dimulai dan diikat, kemudian jika layanan telah dimulai, sistem tidak akan menghapus layanan ketika semua klien melepas ikatan. Sebaliknya, Anda harus menghentikan layanan secara eksplisit, dengan memanggil stopSelf() atau stopService().

Walaupun Anda biasanya harus mengimplementasikan onBind() atau onStartCommand(), kadang-kadang perlu mengimplementasikan keduanya. Misalnya, sebuah pemutar musik bisa merasakan manfaatnya karena layanannya boleh berjalan terus-menerus dan juga menyediakan pengikatan. Dengan cara ini, sebuah aktivitas bisa memulai layanan untuk memutar beberapa lagu dan musik terus dimainkan sekalipun pengguna meninggalkan aplikasi. Lalu, bila pengguna kembali ke aplikasi, aktivitas bisa mengikat ke layanan untuk mendapatkan kembali kontrol atas pemutaran.

Untuk informasi selengkapnya tentang daur hidup layanan saat menambahkan pengikatan ke layanan yang sudah dimulai, lihat Mengelola daur hidup Layanan terikat.

Klien mengikat layanan dengan memanggil bindService(). Bila itu dilakukan, klien harus menyediakan implementasi ServiceConnection, yang memantau koneksi dengan layanan. Nilai hasil bindService() menunjukkan apakah layanan yang diminta ada dan apakah klien diziinkan mengaksesnya. Saat sistem Android membuat koneksi antara klien dan layanan, sistem tersebut memanggil onServiceConnected() pada ServiceConnection. Metode onServiceConnected() berisi argumen IBinder, yang kemudian digunakan klien untuk berkomunikasi dengan layanan terikat.

Anda bisa menghubungkan beberapa klien ke layanan secara bersamaan. Akan tetapi, sistem melakukan cache pada saluran komunikasi layanan IBinder. Dengan kata lain, sistem memanggil metode onBind() layanan untuk membuat IBinder hanya ketika klien pertama mengikat. Sistem kemudian memberikan IBinder yang sama ke semua klien tambahan yang mengikat ke layanan yang sama, tanpa memanggil onBind() lagi.

Bila klien terakhir melepas ikatan dari layanan, sistem akan menghapus layanan, kecuali jika layanan juga dimulai oleh startService().

Bagian terpenting adalah mendefinisikan antarmuka yang dikembalikan metode callback onBind() Anda. Bagian berikut membahas beragam cara untuk menentukan antarmuka IBinder layanan Anda.

Membuat layanan terikat

Saat membuat layanan yang menyediakan pengikatan, Anda harus menyediakan IBinder yang menyediakan antarmuka pemrograman yang bisa digunakan klien untuk berinteraksi dengan layanan. Ada tiga cara untuk menentukan antarmuka:

Memperluas class Binder
Jika layanan Anda bersifat privat untuk aplikasi Anda sendiri dan berjalan dalam proses yang sama dengan klien (biasanya), Anda harus membuat antarmuka dengan memperluas class Binder dan mengembalikan instance dari onBind(). Klien akan menerima Binder dan bisa menggunakannya untuk mengakses langsung metode publik yang tersedia dalam implementasi Binder atau Service.

Inilah teknik yang lebih disukai bila layanan Anda sekadar pekerja latar belakang untuk aplikasi Anda sendiri. Satu-satunya alasan tidak membuat antarmuka dengan cara ini adalah karena layanan Anda akan digunakan oleh aplikasi lain atau pada proses-proses terpisah.

Menggunakan Messenger
Jika antarmuka Anda perlu bekerja lintas proses yang berbeda, Anda bisa membuat antarmuka untuk layanan dengan Messenger. Dengan cara ini, layanan mendefinisikan Handler yang akan merespons beragam tipe objek Message. Handler ini adalah dasar bagi Messenger yang nanti bisa berbagi IBinder dengan klien, sehingga memungkinkan klien mengirim perintah ke layanan dengan menggunakan objek Message. Selain itu, klien bisa mendefinisikan sendiri Messenger, sehingga layanan bisa mengirim balik pesan.

Inilah cara termudah melakukan komunikasi antarproses (IPC), karena Messenger akan membuat antrean semua permintaan ke dalam satu thread sehingga Anda tidak perlu mendesain layanan agar thread-safe.

Menggunakan AIDL
AIDL (Android Interface Definition Language) mengurai objek menjadi primitif yang bisa dipahami dan diarahkan oleh sistem operasi ke berbagai proses untuk melakukan IPC. Teknik sebelumnya, yang menggunakan Messenger, sebenarnya berdasarkan AIDL sebagai struktur yang mendasarinya. Seperti disebutkan di atas, Messenger membuat antrean semua permintaan klien dalam satu thread, sehingga layanan akan menerima permintaan satu per satu. Akan tetapi, jika ingin layanan Anda menangani beberapa permintaan sekaligus, Anda bisa menggunakan AIDL secara langsung. Dalam hal ini, layanan Anda harus berupa thread-safe dan mampu multi-thread.

Untuk menggunakan AIDL secara langsung, Anda harus membuat file .aidl yang menetapkan antarmuka pemrograman. Fitur Android SDK menggunakan file ini untuk menghasilkan class abstrak yang mengimplementasikan antarmuka dan menangani IPC, yang nanti bisa Anda perluas dalam layanan.

Catatan: Umumnya aplikasi tidak boleh menggunakan AIDL untuk membuat layanan terikat, karena hal itu mungkin memerlukan kemampuan multi-thread dan bisa mengakibatkan implementasi yang lebih rumit. Dengan demikian, AIDL tidak cocok untuk sebagian besar aplikasi dan dokumen ini tidak membahas cara menggunakannya untuk layanan Anda. Jika Anda yakin perlu menggunakan AIDL secara langsung, lihat dokumen AIDL.

Memperluas class Binder

Jika layanan Anda hanya digunakan oleh aplikasi lokal dan tidak perlu bekerja lintas proses, maka Anda bisa mengimplementasikan class Binder Anda sendiri yang memberi klien Anda akses langsung ke metode publik dalam layanan.

Catatan: Hal ini hanya berhasil jika klien dan layanan berada dalam aplikasi dan proses yang sama, suatu kondisi yang paling umum. Misalnya, cara ini sangat cocok untuk sebuah aplikasi musik yang perlu mengikat aktivitas ke layanannya sendiri, yakni memutar musik di latar belakang.

Berikut cara menyiapkannya:

  1. Dalam layanan Anda, buat sebuah instance Binder yang melakukan salah satu dari berikut:
    • Berisi metode publik yang bisa dipanggil klien.
    • Mengembalikan instance Service saat ini, yang memiliki metode publik yang bisa dipanggil klien.
    • Mengembalikan instance class lain yang di-host di layanan dengan metode publik yang bisa dipanggil klien.
  2. Kembalikan instance Binder ini dari metode callback onBind().
  3. Di klien, terima Binder dari metode callback onServiceConnected() dan buat panggilan ke layanan terikat dengan menggunakan metode yang disediakan.

Catatan: Layanan dan klien harus berada di aplikasi yang sama sehingga klien bisa mentransmisikan objek yang dikembalikan dan memanggil API-nya dengan benar. Layanan dan klien juga harus berada dalam proses yang sama, karena teknik ini tidak melakukan pengarahan (marshalling) apa pun pada proses.

Misalnya, berikut ini layanan yang memberi klien akses ke metode-metode dalam layanan melalui implementasi 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 menyediakan metode getService() bagi klien untuk mengambil instance LocalService saat ini. Cara ini memungkinkan klien memanggil metode publik dalam layanan. Misalnya, klien bisa memanggil getRandomNumber() dari layanan.

Berikut ini aktivitas yang mengikat ke LocalService dan memanggil getRandomNumber() bila tombol diklik:

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 were something that might hang, then this request should
            // occur 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 were something that might hang, then this request should
            // occur 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;
        }
    };
}

Contoh di atas menampilkan cara klien mengikat ke layanan dengan menggunakan implementasi ServiceConnection dan callback onServiceConnected(). Bagian berikut menyediakan informasi selengkapnya tentang proses pengikatan ke layanan.

Catatan: Dalam contoh di atas, metode onStop() akan melepas klien dari layanan. Klien harus lepas dari layanan pada waktu yang tepat, seperti yang dibahas dalam Catatan Tambahan.

Untuk kode contoh selengkapnya, lihat class LocalService.java dan kelas LocalServiceActivities.java dalam ApiDemos.

Menggunakan Messenger

Jika layanan perlu berkomunikasi dengan proses jauh, Anda bisa menggunakan Messenger untuk menyediakan antarmuka bagi layanan Anda. Teknik ini memungkinkan Anda melakukan komunikasi antarproses (IPC) tanpa harus menggunakan AIDL.

Menggunakan Messenger untuk antarmuka Anda lebih mudah dari menggunakan AIDL karena Messenger membuat antrean semua panggilan ke layanan. Antarmuka AIDL murni mengirim permintaan secara bersamaan ke layanan, yang kemudian harus menangani multi-thread.

Untuk sebagian besar aplikasi, layanan tidak perlu melakukan multi-threading, jadi menggunakan Messenger memungkinkan layanan menangani panggilan satu per satu. Jika layanan harus multi-thread, gunakan AIDL untuk menetapkan antarmuka.

Berikut ini rangkuman cara menggunakan Messenger:

  1. Layanan mengimplementasikan Handler yang menerima callback untuk tiap panggilan dari klien.
  2. Layanan menggunakan Handler untuk membuat objek Messenger (yang merupakan acuan ke Handler).
  3. Messenger membuat IBinder yang dikembalikan layanan ke klien dari onBind().
  4. Klien menggunakan IBinder untuk membuat instance Messenger (yang mengacu Handler layanan), yang digunakan klien untuk mengirim objek Message ke layanan.
  5. Layanan menerima setiap Message dalam Handler—secara spesifik, dalam metode handleMessage().

Dengan cara ini, tidak ada metode untuk dipanggil klien pada layanan. Sebagai gantinya, klien mengirim pesan (objek-objek Message) yang diterima layanan dalam Handler-nya.

Berikut ini contoh layanan sederhana yang menggunakan antarmuka 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();
    }
}

Perhatikan bahwa metode handleMessage() dalam Handler adalah tempat layanan menerima Message yang masuk dan memutuskan aksi yang harus dilakukan, berdasarkan anggota what.

Klien tinggal membuat Messenger berdasarkan IBinder yang dikembalikan oleh layanan dan mengirim pesan menggunakan send(). Misalnya, inilah aktivitas sederhana yang mengikat ke layanan dan mengirim pesan MSG_SAY_HELLO ke layanan:

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;
        }
    }
}

Perhatikan bahwa contoh ini tidak menampilkan cara layanan merespons klien. Jika ingin layanan merespons, Anda juga perlu membuat Messenger di klien. Saat klien menerima callback onServiceConnected(), klien akan mengirim Message ke layanan yang berisi Messenger klien dalam parameter replyTo metode send().

Anda bisa melihat contoh cara menyediakan perpesanan dua arah dalam contoh MessengerService.java (layanan) dan MessengerServiceActivities.java (klien).

Mengikat ke layanan

Komponen-komponen aplikasi (klien) bisa mengikat ke layanan dengan memanggil bindService(). Sistem Android kemudian memanggil onBind() layanan, yang mengembalikan IBinder untuk berinteraksi dengan layanan.

Pengikatan tersebut tidak bersamaan, dan bindService() segera kembali tanpa mengembalikan IBinder ke klien. Untuk menerima IBinder, klien harus membuat instance ServiceConnection dan meneruskannya ke bindService(). ServiceConnection berisi metode callback yang dipanggil sistem untuk mengirim IBinder.

Catatan: Hanya aktivitas, layanan, dan penyedia materi yang bisa mengikat ke layanan—yang tidak bisa Anda ikat ke layanan dari penerima siaran.

Jadi, untuk mengikat layanan dari klien, Anda harus:

  1. Implementasikan ServiceConnection.

    Implementasi Anda harus mengganti dua metode callback:

    onServiceConnected()
    Sistem memanggil ini untuk mengirim IBinder yang dikembalikan oleh metode onBind() layanan.
    onServiceDisconnected()
    Sistem Android memanggil ini bila koneksi ke layanan putus tanpa terduga, seperti ketika layanan mogok atau dimatikan. Ini tidak dipanggil ketika klien melepas ikatan.
  2. Panggil bindService(), dengan meneruskan implementasi ServiceConnection.

    Catatan: Jika metode kembali ke false, klien Anda tidak memiliki koneksi yang valid ke layanan. Namun, klien Anda tetap harus memanggil unbindService(); jika tidak, klien Anda akan menjaga agar layanan tidak dimatikan saat sedang diam.

  3. Bila sistem memanggil metode callback onServiceConnected(), Anda bisa mulai membuat panggilan ke layanan, dengan menggunakan metode yang ditetapkan oleh antarmuka.
  4. Untuk memutus koneksi dari layanan, panggil unbindService().

    Jika klien Anda tetap terikat ke layanan saat aplikasi Anda menghapus klien, penghapusan tersebut akan menyebabkan ikatan klien terputus. Praktik yang lebih baik adalah memutus ikatan klien begitu selesai berinteraksi dengan layanan. Hal itu memungkinkan layanan yang menganggur untuk dimatikan. Untuk informasi selengkapnya tentang waktu yang tepat untuk mengikat dan melepas, lihat Catatan tambahan.

Contoh berikut menghubungkan klien ke layanan yang dibuat di atas dengan memperluas kelas Binder, sehingga tinggal mentransmisikan IBinder yang dikembalikan ke kelas LocalService dan meminta instance 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;
    }
};

Dengan ServiceConnection ini, klien bisa mengikat ke layanan dengan meneruskannya ke bindService(), seperti yang ditampilkan di contoh berikut:

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);
  • Parameter pertama bindService() adalah sebuah Intent yang secara eksplisit menyebutkan layanan yang akan diikat.

    Perhatian: Jika Anda menggunakan intent untuk mengikat ke Service, pastikan bahwa aplikasi Anda aman dengan menggunakan intent eksplisit. Menggunakan maksud implisit untuk memulai layanan akan menimbulkan bahaya keamanan karena Anda tidak bisa memastikan layanan apa yang akan merespons intent, dan pengguna tidak bisa melihat layanan mana yang dimulai. Mulai dari Android 5.0 (API level 21), sistem melontarkan pengecualian jika Anda memanggil bindService() dengan intent implisit.

  • Parameter kedua adalah objek ServiceConnection.
  • Parameter ketiga adalah tanda (flag) yang menunjukkan opsi pengikatan. Tanda biasanya harus berupa BIND_AUTO_CREATE untuk membuat layanan jika belum aktif. Nilai yang memungkinkan lainnya adalah BIND_DEBUG_UNBIND dan BIND_NOT_FOREGROUND, atau 0 bila tidak satu pun.

Catatan tambahan

Berikut ini beberapa catatan penting tentang mengikat ke layanan:

  • Anda harus selalu menjebak pengecualian DeadObjectException, yang dilontarkan jika koneksi terputus. Inilah satu-satunya pengecualian yang dilontarkan oleh metode jauh.
  • Objek adalah acuan yang dihitung lintas proses.
  • Anda biasanya harus memasangkan pengikatan dan pelepasan ikatan selama memasangkan momen membuat dan menghapus daur hidup klien, seperti yang diuraikan dalam contoh berikut:
    • Jika Anda hanya perlu berinteraksi dengan layanan saat aktivitas terlihat, Anda harus mengikat selama onStart() dan melepas ikatan selama onStop().
    • Jika Anda ingin aktivitas menerima tanggapan bahkan saat dihentikan di latar belakang, Anda bisa mengikat selama onCreate() dan melepas ikatan selama onDestroy(). Berhati-hatilah karena hal ini menyiratkan aktivitas Anda perlu menggunakan layanan selama dijalankan (sekalipun di latar belakang), jadi jika layanan berada dalam proses lain, Anda meningkatkan bobot proses dan semakin besar kemungkinan sistem akan mematikannya.

    Catatan: Anda biasanya tidak boleh mengikat dan melepas ikatan selama onResume() aktivitas Anda dan onPause(), karena callback ini terjadi pada setiap transisi daur hidup dan Anda harus menjaga pemrosesan yang terjadi pada transisi ini tetap minim. Juga, jika banyak aktivitas dalam aplikasi Anda mengikat ke layanan yang sama dan ada transisi antara dua aktivitas, layanan bisa dihapus dan dibuat lagi sembari aktivitas saat ini melepas ikatan (selama jeda) sebelum aktivitas berikutnya mengikat (selama lanjutkan). Transisi aktivitas ini untuk cara aktivitas mengoordinasikan daur hidupnya dijelaskan dalam dokumen Aktivitas.

Untuk contoh kode selengkapnya, yang menampilkan cara mengikat ke layanan, lihat kelas RemoteService.java dalam ApiDemos.

Mengelola daur hidup layanan terikat

Bila layanan dilepas ikatannya dari semua klien, sistem Android akan menghapusnya (kecuali jika layanan juga dimulai dengan onStartCommand()). Dengan demikian, Anda tidak harus mengelola daur hidup layanan jika layanan itu murni sebuah layanan terikat—yang dikelola sistem Android untuk Anda berdasarkan apakah layanan terikat ke klien atau tidak.

Akan tetapi, Jika Anda memilih untuk mengimplementasikan metode callback onStartCommand(), maka Anda harus menghentikan layanan secara eksplisit, karena layanan sekarang dianggap telah dimulai. Dalam hal ini, layanan akan berjalan hingga menghentikan dirinya sendiri dengan stopSelf() atau komponen lain memanggil stopService(), terlepas dari apakah layanan terikat ke klien atau tidak.

Selain itu, jika layanan Anda telah dimulai dan menerima pengikatan, maka saat sistem memanggil metode onUnbind(), Anda bisa memilih untuk mengembalikan true jika ingin menerima panggilan ke onRebind() bila nanti klien mengikat ke layanan. onRebind() akan mengembalikan void, namun klien tetap menerima IBinder dalam callback onServiceConnected(). Gambar di bawah ini mengilustrasikan logika untuk jenis daur hidup ini.

Gambar 1. Daur hidup untuk layanan yang dimulai dan juga memungkinkan pengikatan.

Untuk informasi selengkapnya tentang daur hidup layanan yang telah dimulai, lihat dokumen Layanan.