Reputation: 2065
I am new to Jetpack Compose and Kotlin, but I am trying to develop a mobile app using recently stable Jetpack Compose v1.0.0.0
I am using the NavController
for navigation and my screens are made using composable functions.
Because my screen itself is a composable function, I am not able to understand how I can load some API/DB data on composable function entry.
I tried to read about LaunchedEffect
, but don't know if that is the right approach and it also appeared complex to implement.
Here is the sample code:
DemoScreen.kt
: Consider this as a screen that is my startDestination
in NavHost
.
@Composable fun DemoScreen(navController: NavController) {
var json = "Placeholder content, to be updated on screen load and refreshed every x seconds..."
//1. Make network or DB call as soon as entering this composable and store in the "json" variable
//makeDataLoadCallOnEntry() //something like this, and show processing indicator...
//2. And then keep refreshing/updating the content of the "json" variable by calling this
//function in a timer
Box(modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
){
//region #Region: Main content area
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 0.dp)
//.padding(top = 120.dp)
) {
TextField(
value = json,
onValueChange = { json = it },
singleLine = false,
modifier = Modifier
.fillMaxWidth()
.padding(5.dp)
.height(500.dp),
maxLines = 10,
)
val coroutineScope = rememberCoroutineScope()
Button(
onClick = {
coroutineScope.launch {
withContext(Dispatchers.IO) {
try {
//do something in button click
} catch (e: Exception) {
// handle exception
Log.d("button", e.message.toString())
} finally {
//do something
Log.d("button", "in finally")
}
}
}
},
modifier = Modifier
.fillMaxWidth()
.padding(5.dp)
.height(100.dp)
) {
Text(text = "Demo Button")
}
}
//endregion
}
}
And my NavHost
looks like this (this is working fine):
@Composable fun NavigationMaster() { val navController = rememberNavController() val defaultScreen = Screens.DemoScreen.route
NavHost(
navController = navController,
startDestination = defaultScreen){
composable(
route = Screens.DemoScreen.route
){
DemoScreen(navController = navController)
}
}
}
How can I call a function on my DemoScreen
composable entry to have the data from my API prior to the screen is rendered.
If I can get the above, then I think I should be able to implement the timer part to automatically refresh the data from API using a loop and/or timer.
Here is a demo screenshot of how this screen currently looks (the Demo Button does not do anything, please ignore it):
Upvotes: 6
Views: 6698
Reputation: 6835
Simplest approach is to load it just after calling super.onCreate(...)
in the start of the onCreate
block, in your main activity. About the refresh thing, you could just use a loop.
Upvotes: 0
Reputation: 87774
You can do it using view model, something like this:
@Composable
fun DemoScreen() {
val viewModel = viewModel<DemoScreenViewModel>()
when (val state = viewModel.state.collectAsState().value) {
DemoScreenViewModel.State.Loading -> {
Text("Loading")
}
is DemoScreenViewModel.State.Data -> {
DemoScreenContent(state.data)
}
}
}
class DemoScreenViewModel : ViewModel() {
sealed class State {
object Loading: State()
data class Data(val data: String): State()
}
private var _state = MutableStateFlow<State>(State.Loading)
val state = _state.asStateFlow()
init {
viewModelScope.launch {
while (isActive) {
val data = makeDataLoadCallOnEntry()
_state.value = State.Data(data)
// wait one minute and repeat your request
delay(60 * 1000L)
}
}
}
suspend fun makeDataLoadCallOnEntry(): String {
delay(1000)
return "Hello world"
}
}
Upvotes: 11