The*_*bal 5 android kotlin android-jetpack-compose jetpack-compose-navigation compose-recomposition
这是导致无限重组问题的代码
主要活动
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
val viewModel : MainViewModel by viewModel()
val state by viewModel.state.observeAsState()
NavHost(navController = navController, startDestination = "firstScreen") {
composable("firstScreen") { FirstScreen(
navigate = {
navController.navigate("secondScreen")
}, updateState = {
viewModel.getState()
},
state
)}
composable("secondScreen") { SecondScreen() }
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
视图模型
class MainViewModel : ViewModel() {
//var state = MutableStateFlow(0)
private val _state = MutableLiveData(0)
val state: LiveData<Int> = _state
fun getState() {
_state.value = 1
}
}
Run Code Online (Sandbox Code Playgroud)
第一屏
@Composable
fun FirstScreen(
navigate: () -> Unit,
updateState: () -> Unit,
state: Int?
) {
Log.e("state",state.toString())
Button(onClick = {
updateState()
}) {
Text(text = "aaaaaaaa")
}
if(state == 1) {
Log.e("navigate",state.toString())
navigate()
}
}
Run Code Online (Sandbox Code Playgroud)
第二屏
@Composable
fun SecondScreen() {...}
Run Code Online (Sandbox Code Playgroud)
按下按钮会更改视图模型中的状态,如果它更改为 1,则会触发导航到第二个屏幕,但第一个屏幕会无限重组并阻止整个过程
编辑
@Composable
fun FirstScreen(
navigate: () -> Unit,
updateState: () -> Unit,
state: Int?
) {
Log.e("state",state.toString())
Button(onClick = {
updateState()
}) {
Text(text = "aaaaaaaa")
}
LaunchedEffect(state) {
if (state == 1) {
Log.e("navigate", state.toString())
navigate()
}
}
}
Run Code Online (Sandbox Code Playgroud)
这解决了问题
这是因为您正在基于条件属性进行导航,该FirstScreen
条件属性是可组合项的一部分,并且对该属性的更改超出了范围FirstScreen's
,如果该条件属性的值没有更改,则每次更新时它都会NavHost
在您的casestate
保留1
并将始终执行其块。
if(state == 1) {
...
navigate() // navigation
}
Run Code Online (Sandbox Code Playgroud)
您的经历可以通过以下事件来总结:
FirstScreen
和SecondScreen
(初始NavHost
composition
)FirstScreen
观察一个state
值为0
state
1
单击按钮后变为FirstScreen
re-composes
,满足条件( ),执行当前时间state==1
的导航1st
re-composes
FirstScreen's
state
剩余,1
仍满足条件( ),暂时再次state==1
执行导航2nd
re-composes
FirstScreen's
state
仍为1
,满足条件( state==1
),再次执行本次3rd
导航根据官方文档,
您应该仅将 navigator() 作为回调的一部分调用,而不是作为可组合项本身的一部分,以避免在每次重组时调用 navigator()。
我建议将其视为navigation
一次性事件,在内部进行LaunchedEffect
并从发射中观察SharedFlow
。以下是解决您问题的简短解决方法。
有一堂密封课UiEvent
,
sealed class UiEvent {
data class Navigate(val params: Any?): UiEvent()
}
Run Code Online (Sandbox Code Playgroud)
ViewModel
像这样修改你的
class MainViewModel : ViewModel() {
...
private val _oneTimeEvent = MutableSharedFlow<UiEvent>()
val oneTimeEvent = _oneTimeEvent.asSharedFlow()
...
fun navigate() {
if (_state.value == 1) {
viewModelScope.launch {
_oneTimeEvent.emit(UiEvent.Navigate(1))
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
,然后通过LaunchedEffect
在你的FirstScreen
@Composable
fun FirstScreen(
navigate: () -> Unit,
..
) {
...
...
LaunchedEffect(Unit) {
mainViewModel.oneTimeEvent.collectLatest { uiEvent ->
when (uiEvent) {
is UiEvent.Navigate -> {
navigate()
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1781 次 |
最近记录: |