android - 在 Android 中输入/加载基于 Jetpack Compose 的屏幕时从网络或数据库获取数据
问题描述
我是 Jetpack Compose 和 Kotlin 的新手,但我正在尝试使用最近稳定的 Jetpack Compose v1.0.0.0开发移动应用程序
我正在使用NavController
导航,我的屏幕是使用可组合功能制作的。
因为我的屏幕本身是一个可组合函数,所以我无法理解如何在可组合函数条目上加载一些 API/DB 数据。
我试图阅读关于LaunchedEffect
,但不知道这是否是正确的方法,而且实现起来也很复杂。
这是示例代码:
DemoScreen.kt
: 认为这是我的startDestination
屏幕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 }
}
我的
NavHost
样子是这样的(这很好用):@Composable fun NavigationMaster() { val navController = rememberNavController() val defaultScreen = Screens.DemoScreen.route
NavHost( navController = navController, startDestination = defaultScreen){ composable( route = Screens.DemoScreen.route ){ DemoScreen(navController = navController) } }
}
如何在
DemoScreen
可组合条目上调用函数以在呈现屏幕之前获取来自我的 API 的数据。如果我能得到以上信息,那么我认为我应该能够实现计时器部分,以使用循环和/或计时器自动刷新来自 API 的数据。
这是此屏幕当前外观的演示屏幕截图(演示按钮不执行任何操作,请忽略它):
解决方案
您可以使用view model来做到这一点,如下所示:
@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"
}
}
推荐阅读
- c# - 有没有办法对 LINQ 查询进行分组/整理,例如多个 .Include 调用?
- firebase - Flutter 谷歌分析文档
- excel - Excel VBA change shape fill to an image in a loop
- android - 如何使用菜单项在 MaterialToolbar 中创建 SearchView
- python - ValueError: Failed to convert a NumPy array to a Tensor (Unsupported object type BatchEncoding)
- php - How to make a string run as code so it runs a function in php?
- node-pg-migrate - node-pg-migrate doesn't use config.json file
- node.js - How to deploy MERN stack with multi-tanent archtecture?
- python - Website login not working with selenium/python?
- sql-server - Difference between begin transaction and begin atomic