Reputation: 452
I am working on an android application and currently binding to my location service from which i receive location updates while inside the activity, and i wanted to do so from inside a composable after a user has finished the authentication proces
Upvotes: 2
Views: 2713
Reputation: 610
I haven't tested this, but feel free to try, if required it could be adapted for remote services that expose a Messenger. Anyway here's the gist:
package com.example.app
import android.app.Service
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Binder
import android.os.IBinder
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisallowComposableCalls
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
@Composable
inline fun <reified BoundService : Service, reified BoundServiceBinder : Binder> rememberBoundLocalService(
crossinline getService: @DisallowComposableCalls BoundServiceBinder.() -> BoundService,
): BoundService? {
val context: Context = LocalContext.current
var boundService: BoundService? by remember(context) { mutableStateOf(null) }
val serviceConnection: ServiceConnection = remember(context) {
object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
boundService = (service as BoundServiceBinder).getService()
}
override fun onServiceDisconnected(arg0: ComponentName) {
boundService = null
}
}
}
DisposableEffect(context, serviceConnection) {
context.bindService(Intent(context, BoundService::class.java), serviceConnection, Context.BIND_AUTO_CREATE)
onDispose { context.unbindService(serviceConnection) }
}
return boundService
}
Then:
package com.example.app
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import kotlin.random.Random
class RandomNumberService : Service() {
private val binder = LocalBinder()
private val randomNumberGenerator = Random(seed = 100)
val randomNumber: Int
get() = randomNumberGenerator.nextInt()
inner class LocalBinder : Binder() {
val service: RandomNumberService
get() = this@RandomNumberService
}
override fun onBind(intent: Intent): IBinder = binder
}
@Composable
fun RandomNumberServiceExample() {
val randomNumberService = rememberBoundLocalService<RandomNumberService, RandomNumberService.LocalBinder> { service }
Text(
text = randomNumberService?.randomNumber?.toString().orEmpty(),
)
}
If it works I'll update this answer.
Upvotes: 6