(I'm new to Android development, so this might be a basic question. I've searched the best I can.)
I'm relying on a service that updates data asynchronously and provides a callback when there is new data. I'm trying to figure out how to use this to update my UI whenever the data changes.
I've gone through the basic Jetpack Compose tutorials and I can build a UI with a button that updates a count. Based on that knowledge, the best idea I came up with is to create a MutableState in the ComponentActivity's init method. This is working, but I don't know if it's the right way to do this.
Here's my code (obfuscated a bit to remove private details):
class MainActivity : ComponentActivity() {
// Get the updating value from the async service
private val asyncService = getAsyncService()
private val updatingValue = asyncService.getUpdatingValue()
// Create a MutableState for the UI
private val mutableValue = mutableStateOf(updatingValue.value)
init {
// Update the MutableState whenever the value changes
updatingValue.onUpdate { newValue ->
run {
mutableValue.value = newValue
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ExampleComponent(mutableValue)
}
}
}
@Composable
fun ExampleComponent(value: MutableState<String>) {
Text("The value is : ${value.value}")
}
Is this right or is there a better way to do this?
Update:
I wrote a ViewModel class like this and it works great:
class AsyncDataViewModel : ViewModel() {
private val asyncService = getAsyncService()
private val updatingValue = asyncService.getUpdatingValue()
val value = mutableStateOf(updatingValue.value)
init {
updatingValue.onUpdate { updatedValue ->
run {
value.value = updatedValue.value
}
}
}
}
With Jetpack Compose, you should use a ViewModel to manage the data that is displayed, as explained in this lab. A ViewModel
I provided a sample architecture below:
class MyViewModel(
private val asyncService: AsyncService // using Koin dependency injection
) : ViewModel() {
private val _mutableValue = mutableStateOf("") // for write operations
val mutableValue: String = _mutableValue // for read operations
init {
this.loadValue()
}
fun loadValue() {
viewModelScope.launch(Dispatchers.IO) {
// You have a CoroutineScope here. You can execute async suspension functions here.
// call suspension function in AsnycService class
_mutableValue = asyncService.getUpdatingValue()
}
}
}
Then, you can get your ViewModel in your Composable like this:
@Composable
fun MyScreen(
amyViewModel: MyViewModel = viewModel()
) {
Text("The value is : ${myViewModel.mutableValue}")
}
Your service class should use a suspension function. Your ViewModel will call this function as a Coroutine without blocking the UI thread and will update the value and refresh the value automatically:
class AsyncService {
suspend fun getUpdatingValue(): String {
delay(5000) // some long running operation
return "HELLO" // value that is returned after operation
}
}
This way, you also get rid of specifying callback functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With