在 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平台的刷新加载形式初探

基于Android官方AsyncListUtil优化改进RecyclerView分页加载机制

基于Android官方Paging Library的RecyclerView分页加载框架

Android图片加载神器之Fresco,基于各种使用场景的讲解