Android 中基于 Jetpack Compose 的屏幕的 entry/load 从网络或数据库获取数据

Get data from network or database on entry/load of a Jetpack Compose based screen in Android

我是 Jetpack Compose 和 Kotlin 的新手,但我正在尝试使用最近 stable Jetpack Compose v1.0.0.0

开发移动应用程序

我正在使用 NavController 进行导航,我的屏幕是使用可组合函数制作的。

因为我的屏幕本身就是一个可组合函数,所以我无法理解如何在可组合函数条目上加载一些 API/DB 数据。

我试图阅读有关 LaunchedEffect 的内容,但不知道这是否是正确的方法,而且实施起来似乎也很复杂。

示例代码如下:

  1. 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
     }
    

    }

  2. 我的 NavHost 看起来像这样(工作正常):

    @可组合 有趣的 NavigationMaster() { val navController = rememberNavController() val defaultScreen = Screens.DemoScreen.route

     NavHost(
         navController = navController,
         startDestination = defaultScreen){
    
         composable(
             route = Screens.DemoScreen.route
         ){
             DemoScreen(navController = navController)
         }
    
    
     }
    

    }

  3. 如何在我的 DemoScreen 可组合条目上调用一个函数,以便在呈现屏幕之前从我的 API 获取数据。

  4. 如果我能得到上面的,那么我想我应该能够实现定时器部分,使用循环 and/or 定时器自动刷新来自 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"
    }
}

最简单的方法是在您的 main activity 中的 onCreate 块的开头调用 super.onCreate(...) 后立即加载它。关于刷新的事情,你可以只使用一个循环。