在 Android 中输入/加载基于 Jetpack Compose 的屏幕时从网络或数据库获取数据
Posted
技术标签:
【中文标题】在 Android 中输入/加载基于 Jetpack Compose 的屏幕时从网络或数据库获取数据【英文标题】:Get data from network or database on entry/load of a Jetpack Compose based screen in Android 【发布时间】:2021-10-14 13:03:15 【问题描述】:我是 Jetpack Compose 和 Kotlin 的新手,但我正在尝试使用最近稳定的 Jetpack Compose v1.0.0.0
开发一个移动应用程序我正在使用NavController
进行导航,并且我的屏幕是使用可组合函数制作的。
由于我的屏幕本身是一个可组合函数,我无法理解如何在可组合函数条目上加载一些 API/DB 数据。
我尝试阅读有关 LaunchedEffect
的信息,但不知道这是否是正确的方法,而且实施起来似乎也很复杂。
这里是示例代码:
DemoScreen.kt
:将其视为我在NavHost
中的startDestination
的屏幕。
@可组合 有趣的 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
看起来像这样(这工作正常):
@可组合 有趣的导航大师() val navController = rememberNavController() val defaultScreen = Screens.DemoScreen.route
NavHost(
navController = navController,
startDestination = defaultScreen)
composable(
route = Screens.DemoScreen.route
)
DemoScreen(navController = navController)
如何在我的 DemoScreen
可组合条目上调用一个函数,以便在呈现屏幕之前从我的 API 获取数据。
如果我能获得以上信息,那么我认为我应该能够实现计时器部分,以使用循环和/或计时器自动刷新来自 API 的数据。
这里是这个屏幕当前外观的演示截图(演示按钮不做任何事情,请忽略它):
【问题讨论】:
【参考方案1】:您可以使用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"
【讨论】:
如果您想在按钮单击时进行后续网络调用怎么办?例如,用户单击可组合组件上的登录按钮,然后它会进行另一个网络调用并导航到主屏幕?【参考方案2】:最简单的方法是在您的主活动中,在onCreate
块的开头调用super.onCreate(...)
之后立即加载它。关于刷新的事情,你可以只使用一个循环。
【讨论】:
谢谢Marsk,但另一个答案适合我的需要。我还想将 API 部分保留在“相关”可组合函数中,因为它可以是任何屏幕,而不仅仅是 MainActivity 之后的第一个屏幕。以上是关于在 Android 中输入/加载基于 Jetpack Compose 的屏幕时从网络或数据库获取数据的主要内容,如果未能解决你的问题,请参考以下文章
基于Android官方AsyncListUtil优化经典ListView分页加载机制
Android 插件化基于插件化的恶意软件的加载策略分析 ( 自定义路径加载插件 | 系统路径加载插件 | 用户同意后加载插件 | 隐藏恶意插件 )
基于Android官方AsyncListUtil优化改进RecyclerView分页加载机制