English 中文(简体)
如何使用 Mutiable State StateFlow 更新服务 UI 更新用户界面
原标题:How can i update UI from service using MutableStateFlow
  • 时间:2024-07-01 07:46:03
  •  标签:
`When I running my service, UI not update. Service is running because i see update in my log. This is my simplified example but still it doesn t work. My service has value MutableStateFlow, every 1 second I do emit ` class MyService : Service() { private val _stateFlow = MutableStateFlow(0) val stateFlow: MutableStateFlow = _stateFlow private var i = 0 override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { CoroutineScope(Dispatchers.IO).launch { while (true) { i++ _stateFlow.emit(i) Log.d("service", "emit") delay(1000) } } Log.d("service", "started") return START_STICKY } } class MyViewModel : ViewModel() { private val _serviceData = MutableStateFlow("Initial ViewModel Value") val serviceData: StateFlow = _serviceData fun observeServiceState(service: MyService) { viewModelScope.launch { service.stateFlow.collect { value -> _serviceData.value = value.toString() } } } } @Composable fun MyApp(context: Context) { val serviceIntent = Intent(context, MyService::class.java) context.startService(serviceIntent) MyComposable(service = MyService()) } @Composable fun MyComposable(service: MyService) { val viewModel = MyViewModel() val value by viewModel.serviceData.collectAsState() Text(text = "Current value: $value") viewModel.observeServiceState(service) }
问题回答
currently you are starting your service context.startService(serviceIntent) and in next line you are creating new instance of it for composable MyComposable(service = MyService()) (if this would be Java you would need to write keyword new MyService()) so first instance is running freely, and you are obseving its logs, second one is just created in memory, doesn t run, thus never emit any value through flow, which is observed in ViewModel if you need to reach your flows declared in MyService then wrap them inside companion object note that companion object will survive killing and re-starting service, so you should introduce some resetting-flow code in onCreate and onDestroy
You are starting your service but not binding it. Instead you are creating service class instance on your own which is wrong. Your service should have a binder class like this: class MyService : Service() { inner class MyBinder : Binder() { fun getService() : MyService? { return this@MyService } } // rest of the code } You can get your running service instance using this code: val connection = object: ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { val binder = (MyBinder) service val mService = binder.getService() viewModel.observeServiceState(mService) } override fun onServiceDisconnected(arg0: ComponentName) { // your logic here for handling disconnection } } Finally, for above code to work, you need to start and bind your service like this: LaunchedEffect(key1 = Unit) { bindService(Intent(context, MyService::class.java), connection, Context.BIND_AUTO_CREATE); // dont t forget to unbind the service when you are done. } LaunchedEffect is used to start and bind the service only once, with your current code, the service will start again and again with every recomposition.




相关问题
热门标签