aku*_*ubi 5 android android-jetpack-navigation android-jetpack-compose kotlin-stateflow
我一直在使用 StateFlow + 密封接口来表示 Android 应用程序中的各种 UI 状态。在我的 ViewModel 中,我有一个密封接口UiState
来执行此操作,并且各种状态公开为StateFlow
:
sealed interface UiState {
class LocationFound(val location: CurrentLocation) : UiState
object Loading : UiState
// ...
class Error(val message: String?) : UiState
}
@HiltViewModel
class MyViewModel @Inject constructor(private val getLocationUseCase: GetLocationUseCase): ViewModel() {
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState
// ...
}
Run Code Online (Sandbox Code Playgroud)
然后在可组合项中,我以这种方式观察事件:
@Composable
fun MyScreen(
viewModel: HomeScreenViewModel,
onLocationFound: (CurrentLocation) -> Unit,
onSnackbarButtonClick: () -> Unit
) {
// ...
LaunchedEffect(true) { viewModel.getLocation() }
when (val state = viewModel.uiState.collectAsState().value) {
is UiState.LocationFound -> {
Log.d(TAG, "MyScreen: LocationFound")
onLocationFound.invoke(state.location)
}
UiState.Loading -> LoadingScreen
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
在我的 MainActivity.kt 中,当onLocationFound
调用回调时,我应该导航到Screen2
以下位置中的另一个目的地 ( ) NavGraph
:
enum class Screens {
Screen1,
Screen2,
// ...
}
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
MyTheme {
MyNavHost(navController = navController)
}
}
}
}
@Composable
fun MyNavHost(navController: NavHostController) {
val context = LocalContext.current
NavHost(navController = navController, startDestination = Screens.Home.name) {
composable(Screens.Screen1.name) {
val viewModel = hiltViewModel<MyViewModel>()
MyScreen(viewModel = viewModel, onLocationFound = {
navController.navigate(
"${Screens.Screen2.name}/${it.locationName}/${it.latitude}/${it.longitude}"
)
}, onSnackbarButtonClick = { // ... }
)
}
// ....
composable("${Screens.Screen2.name}/{location}/{latitude}/{longitude}", arguments = listOf(
navArgument("location") { type = NavType.StringType },
navArgument("latitude") { type = NavType.StringType },
navArgument("longitude") { type = NavType.StringType }
)) {
// ...
}
}
}
Run Code Online (Sandbox Code Playgroud)
但发生的情况是,onLocationFound
回调似乎被击中了多次,因为我可以看到我放置的日志记录在 Logcat 中多次显示,因此我多次导航到同一位置,导致屏幕出现烦人的闪烁。我查了一下 MyViewmodel
,我绝对不会设置_uiState.value = LocationFound
多次。奇怪的是,当我用 包装回调的调用时LaunchedEffect(true)
,LocationFound
只被调用两次,这仍然很奇怪,但至少没有闪烁。
但仍然LocationFound
应该只被调用一次。我有一种感觉,这里正在发挥重构或一些有关 Compose 导航的警告,但我已经研究过,但找不到合适的术语来寻找。
归档时间: |
|
查看次数: |
1049 次 |
最近记录: |