簡體   English   中英

在 jetpack compose 中,UI 狀態無法正常工作

[英]Ui state not working correctly in jetpack compose

我在 jetpack compose 中使用 MutableStateFlow UI State 我的 UI 事件沒有得到正確的流程。 在 UI 狀態中有EmptyLoadingSuccessError狀態。 當我初始化一個變量時,我設置了一個狀態。 當我在此之前開始調用 api 時,我觸發了Loading狀態。 在此基礎上,我觸發了SuccessError事件。

注意:我沒有添加導入和包名稱。 如果您想查看完整代碼,請單擊您將重定向到我的存儲庫的類名稱。

MainActivityViewModel.kt

class MainActivityViewModel(private val resultRepository: ResultRepository) : ViewModel() {

    val stateResultFetchState = MutableStateFlow<ResultFetchState>(ResultFetchState.OnEmpty)

    fun getSportResult() {
        viewModelScope.launch {
            stateResultFetchState.value = ResultFetchState.IsLoading
            val result = resultRepository.getSportResult()
            delay(5000)
            result.handleResult(
                onSuccess = { response ->
                    if (response != null) {
                        stateResultFetchState.value = ResultFetchState.OnSuccess(response)
                    } else {
                        stateResultFetchState.value = ResultFetchState.OnEmpty
                    }
                },
                onError = {
                    stateResultFetchState.value =
                        ResultFetchState.OnError(it.errorResponse?.errorMessage)
                }
            )
        }
    }
}

MainActivity.kt

internal lateinit var networkConnection: NetworkConnection

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        networkConnection = NetworkConnection(application)
        setContent {
            SportsResultTheme {
                SetupConnectionView()
            }
        }
    }
}

@Composable
fun SetupConnectionView() {
    val isConnected = networkConnection.observeAsState()
    if (isConnected.value == true) {
        NavigationGraph()
    } else {
        NoInternetView()
    }
}

@Composable
fun NoInternetView() {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(getBackgroundColor()),
        contentAlignment = Center,

        ) {
        val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.nointernet))
        LottieAnimation(
            composition,
            iterations = LottieConstants.IterateForever
        )
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SetupMainActivityView(
    viewModel: MainActivityViewModel = koinViewModel(),
    navigateToNext: (state: String) -> Unit,
) {
    Scaffold(topBar = {
        TopAppBar(
            title = { Text(text = stringResource(id = R.string.app_name)) },
            backgroundColor = getBackgroundColor(),
            elevation = 0.dp
        )
    }, content = { padding ->
        Column(
            modifier = Modifier
                .fillMaxSize()
                .background(getBackgroundColor())
                .padding(padding),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Button(onClick = {
                viewModel.getSportResult()
            }) {
                Text(text = stringResource(id = R.string.get_result))
            }
        }
    })
    when (val state = viewModel.stateResultFetchState.collectAsState().value) {
        is ResultFetchState.OnSuccess -> {
            navigateToNext("loading $state")
        }
        is ResultFetchState.IsLoading -> {
            LoadingFunction()
        }
        is ResultFetchState.OnError -> {}
        is ResultFetchState.OnEmpty -> {}
    }
}


@Composable
fun LoadingFunction() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(getBackgroundColor()),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        CircularProgressIndicator()
    }
}

我正在添加我的導航圖,以便您清楚地看到我正在嘗試做什么。

導航圖.kt

@Composable
internal fun NavigationGraph() {
    val navController = rememberNavController()
    NavHost(navController = navController, startDestination = ScreenRoute.Home.route) {
        composable(ScreenRoute.Home.route) {
            SetupMainActivityView { state ->
                navController.navigate(ScreenRoute.Result.route + "/{$state}")
            }
        }

        composable(
            ScreenRoute.Result.route + "/{state}",
            arguments = listOf(
                navArgument("state") { type = NavType.StringType }
            )
        ) { backStackEntry ->
            ResultScreen(backStackEntry.arguments?.getString("state").orEmpty())
        }
    }
}

結果屏幕.kt

@Composable
fun ResultScreen(state: String) {
    Log.e("TAG", "ResultScreen: $state" )

}

實際輸出

當您單擊Button時,它開始加載屏幕。 加載屏幕后,我的按鈕屏幕出現,而不是我的結果屏幕出現。 你可以在我的視頻中看到。

Button Screen -> Loading Screen -> Again Button Screen -> Result Screen.

預期產出

Button Screen -> Loading Screen -> Result Screen.

我的 Github 項目鏈接 你們能指導我在這里做錯了什么。 非常感謝

在加載期間,您將按鈕視圖與加載視圖重疊,但是當您成功刪除加載視圖時,按鈕視圖會出現以進行轉換。

根據預期的行為,您可以將您的when移動到content中,並僅在空/錯誤時顯示內容 - 保留單擊返回以取消請求的選項可能是有意義的。

content = { padding ->
    Box(Modifier.fillMaxSize().padding(padding).background(getBackgroundColor())) {
        when (val state = viewModel.stateResultFetchState.collectAsState().value) {
            is ResultFetchState.OnSuccess -> {
                LaunchedEffect(Unit){
                    navigateToNext("loading $state")
                }
            }
            is ResultFetchState.IsLoading -> {
                LoadingFunction()
            }
            is ResultFetchState.OnError, is ResultFetchState.OnEmpty -> {
                YourContent()
            }
        }
    }
})

或者在ResultFetchState.OnSuccess中添加LoadingFunction() ,這樣這個視圖就不會在轉換過程中從屏幕上消失。

is ResultFetchState.OnSuccess -> {
    LaunchedEffect(Unit){
        navigateToNext("loading $state")
    }
    LoadingFunction()
}

另請參閱此答案,了解為什么像您一樣調用navigateToNext是不安全的,以及為什么我添加了LaunchedEffect

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM