Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait for service to be bound using coroutines

Tags:

kotlin

So I have a method that binds to the service.

fun bindService() {
        val intent = Intent(this, BluetoothService::class.java)
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
    }

Inside onCreate method I use this code:

 bindService()
        launch {
            delay(500L)
            service = serviceConnection.serviceBinder?.getService() as BluetoothService
        }

Is there more elegant way to wait for the service to be bound than using delay()?

like image 440
dawzaw Avatar asked Jan 22 '18 12:01

dawzaw


People also ask

How do you use coroutines in service?

You can create your own CoroutineScope with a SupervisorJob that you can cancel in the onDestroy() method. The coroutines created with this scope will live as long as your Service is being used. Once onDestroy() of your service is called, all coroutines started with this scope will be cancelled.

How do you wait for coroutine to finish Kotlin?

When we launch a coroutine in Kotlin using launch we are returned the resulting Job . We can wait for the coroutine to finish by calling join() on the Job.

Are coroutines provide asynchronous code without thread blocking?

Coroutines are nothing but lightweight threads. They provide us with an easy way to do synchronous and asynchronous programming. Coroutines allow us to replace callbacks and build the main safety without blocking the main thread.


1 Answers

I wrote this just now, and haven't tried it, but hopefully something like it could work. The magic is in suspendCoroutine, which pauses the current coroutine and then gives you a continuation thingy you can use to resume it later. In our case we resume it when the onServiceConnected is called.

// helper class which holds data
class BoundService(
        private val context: Context,
        val name: ComponentName?, 
        val service: IBinder?, 
        val conn: ServiceConnection) {
    fun unbind() {
        context.unbindService(conn)
    }
}

// call within a coroutine to bind service, waiting for onServiceConnected
// before the coroutine resumes
suspend fun bindServiceAndWait(context: Context, intent: Intent, flags: Int) = suspendCoroutine<BoundService> { continuation ->


    val conn = object: ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            continuation.resume(BoundService(context, name, service, this))
        }
        override fun onServiceDisconnected(name: ComponentName?) {
            // ignore, not much we can do
        }

    }
    context.bindService(intent, conn, flags)
}

// just an example
suspend fun exampleUsage() {
    val bs = bindServiceAndWait(context, intent, Context.BIND_AUTO_CREATE)
    try {
        // ...do something with bs.service...
    } finally {
        bs.unbind()
    }
}
like image 167
lincolnq Avatar answered Sep 30 '22 04:09

lincolnq