繁体   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