Это моя UiModel:
Код: Выделить всё
@Immutable
data class SplashUiModel(
var state: SplashLoadingState = SplashLoadingState.InProgress,
)
sealed interface SplashLoadingState {
object InProgress: SplashLoadingState
object Valid: SplashLoadingState
object Invalid: SplashLoadingState
}
Код: Выделить всё
private val _state: MutableStateFlow = MutableStateFlow(SplashUiModel())
val state = _state.asStateFlow()
Код: Выделить всё
inline fun MutableStateFlow.updateIfDifferent(function: (T) -> T) {
while (true) {
val prevValue = value
val nextValue = function(prevValue)
// Check if the value is actually different before trying to update
if (prevValue == nextValue) {
// No need to update if the value hasn't changed
return
}
// Atomically update the value using compareAndSet
if (compareAndSet(prevValue, nextValue)) {
return
}
}
}
Код: Выделить всё
_state.updateIfDifferent { it.copy(state = SplashLoadingState.Invalid) }
Код: Выделить всё
val state = viewModel.state.collectAsStateWithLifecycle()
Код: Выделить всё
when(state.value) {
SplashLoadingState.Valid -> {
listener.onNavigateValid()
}
SplashLoadingState.Invalid -> {
listener.onNavigateInvalid()
}
SplashLoadingState.InProgress -> {
BaseLoadingIndicator()
}
}
Код: Выделить всё
var hasNavigated by remember { mutableStateOf(false) }
val listener = object : SplashScreenListener {
override fun onNavigateValid() {
if (!hasNavigated) {
hasNavigated = true
onValid.invoke()
}
}
override fun onNavigateInvalid() {
if (!hasNavigated) {
hasNavigated = true
onInvalid.invoke()
}
}
}
Код: Выделить всё
onValid.invoke()
Код: Выделить всё
SplashScreen
Что сейчас со мной происходит то, что onValid вызывается бесконечно, если я меняю состояние на основе ответа на вызов API. И экран постоянно мерцает. Я не понимаю, почему это тот случай, когда я даже добавил флаг hasNavigated, чтобы вызвать этот обратный вызов навигации только один раз. Также updateIfDifferent также должен предотвращать обновление значения, если оно одинаковое (в большинстве случаев это не так, но этот вызов API выполняется только один раз при запуске приложения).
I даже попробуйте использовать LaunchedEffect, чтобы запустить его хотя бы один раз:
Код: Выделить всё
when(state.value) {
SplashLoadingState.Valid -> {
LaunchedEffect(Unit){
listener.onNavigateValid()
}
}
SplashLoadingState.Invalid -> {
LaunchedEffect(Unit){
listener.onNavigateInvalid()
}
}
SplashLoadingState.InProgress -> {
BaseLoadingIndicator()
}
}
ОБНОВЛЕНИЕ:
Хорошо, это звучит безумно, но у меня есть другой экран, на котором переданы пользовательские NavTypes типа Parcelable. (передача объектов данных, содержащих объекты данных, поэтому мне пришлось создать для него собственный NavType). И даже если я не использую его в этой функции обратного вызова, по какой-то причине (возможно, это ошибка NavGraphBuilder или что-то в этом роде), он вызывает рекомпозицию каждого отдельного экрана в моем навигационном графе.
Пример :
Код: Выделить всё
dialog(
typeMap = mapOf(
typeOf
() to CustomNavTypes.parcelableType(),
typeOf() to CustomNavTypes.parcelableType(),
typeOf() to CustomNavTypes.parcelableType()
)
) {
RandomScreenComposable(
viewModel = hiltViewModel(),
)
}
inline fun parcelableType(
isNullableAllowed: Boolean = false,
json: Json = Json,
) = object : NavType(isNullableAllowed = isNullableAllowed) {
override fun get(bundle: Bundle, key: String) =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
bundle.getParcelable(key, T::class.java)
} else {
@Suppress("DEPRECATION")
bundle.getParcelable(key)
}
override fun parseValue(value: String): T = json.decodeFromString(value)
override fun serializeAsValue(value: T): String = json.encodeToString(value)
override fun put(bundle: Bundle, key: String, value: T) = bundle.putParcelable(key, value)
}
Если я не могу использовать в этом пользовательские объекты новая навигация TypeSafe, это усложнит мою жизнь, поскольку мне придется передавать простые типы, такие как Strings и Ints, только между экранами.
Когда я закомментировал эти NavTypes и удалил разделяемый класс данных , на моем SplashScreen все работает нормально.
Подробнее здесь: https://stackoverflow.com/questions/790 ... nges-causi