LivenessScreen(
viewModel = livenessViewModel,
onErrorScreen = onErrorScreen,
onLivenessComplete = onLivenessComplete
)
Проблема:
Когда я передаю onErrorScreen и onLivenessComplete в качестве лямбда-функций в LivenessScreen, случай UiState.Failure запускается несколько раз при следующих условиях:
- При сбое API трижды запускается случай сбоя.
- Когда я нажимаю кнопку «Назад» в системе, возникает случай сбоя. сработало снова.
Наблюдения:
- Из варианта использования состояние сбоя генерируется только один раз в соответствии с к журналы.
- Повторяющиеся триггеры происходят только тогда, когда лямбда-выражения передаются в LivenessScreen.
- Что может быть причиной того, что случай UiState.Failure вызывается
несколько раз? - Как я могу предотвратить повторное срабатывание состояния отказа при
использовании лямбды в Jetpack Compose? - Существуют ли какие-либо передовые методы обработки лямбда-выражений и управления состоянием
, чтобы избежать таких проблем?
MainActivity.kt
setContent {
val navController = rememberNavController()
NavGraph(navController)
}
NavGraph.kt
@Composable
fun NavGraph(navController: NavHostController) {
NavHost(
navController = navController, startDestination = NavRoute.LiveNess.path
) {
addLivenessScreen(navController, this)
addLiveNessSuccessScreen(navController, this)
}
}
fun addLivenessScreen(navController: NavHostController, navGraphBuilder: NavGraphBuilder) {
navGraphBuilder.composable(route = NavRoute.LiveNess.path) {
LivenessRoute(
onLivenessComplete = {
navController.navigate(NavRoute.LiveNessSuccess.path)
},
onErrorScreen = {
navController.navigate(NavRoute.GenericErrorScreen.path)
},
)
}
}
fun addLiveNessSuccessScreen(
navController: NavHostController,
navGraphBuilder: NavGraphBuilder,
config: SDKConfiguration
) {
navGraphBuilder.composable(route = NavRoute.LiveNessSuccess.path) {
LivenessSuccessScreen(
)
}
}
LivenessRoute.kt
@Composable
fun LivenessRoute(
onLivenessComplete: () -> Unit,
onErrorScreen: () -> Unit
) {
val livenessViewModel: LivenessViewModel = koinViewModel()
LivenessScreen(
viewModel = livenessViewModel,
onErrorScreen = onErrorScreen,
onLivenessComplete = onLivenessComplete
)
}
LivenessScreen.kt
@Composable
fun LivenessScreen(
modifier: Modifier = Modifier,
onLivenessComplete: () -> Unit,
onErrorScreen: () -> Unit,
viewModel: LivenessViewModel
) {
val uiState = viewModel.uiState.collectAsStateWithLifecycle()
V2Theme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Box(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding),// Padding for better spacing
contentAlignment = Alignment.Center // Center content within the Box
) {
when (val state = uiState.value) {
is UiState.Loading -> {
Column(
horizontalAlignment = Alignment.CenterHorizontally, // Center items horizontally
verticalArrangement = Arrangement.Center // Center items vertically
) {
CircularProgressIndicator()
Spacer(modifier = Modifier.height(16.dp))
Text("Loading...")
}
}
is UiState.Success -> {
state.value?.sessionId?.let {
Column(
horizontalAlignment = Alignment.CenterHorizontally, // Center items horizontally
verticalArrangement = Arrangement.Center // Center items vertically
) {
CircularProgressIndicator()
Spacer(modifier = Modifier.height(16.dp))
Text("Loading... $it")
}
}
}
is UiState.Failure -> {
Log.d("FaceLivenessDetector", state.exception.toString())
}
}
}
}
}
}
LivenessViewModel.kt
class LivenessViewModel(private val fetchSessionDataUseCase: FetchSessionDataUseCase) :
ViewModel() {
private val _uiState = MutableStateFlow(UiState.Loading)
val uiState: StateFlow get() = _uiState
init {
fetchSessionData()
}
private fun fetchSessionData() {
val request = LivenessRequest(
kmsKeyId = null, // Optional
auditImagesLimit = 3, // Optional
clientRequestToken = generateRandomString(16) // Required
)
viewModelScope.launch {
fetchSessionDataUseCase.invoke(request).collectLatest { apiResult ->
when (apiResult) {
is ApiResult.Success -> {
_uiState.value = UiState.Success(apiResult.value)
}
is ApiResult.Failure -> {
_uiState.value = UiState.Failure(
apiResult.errorType ?: ApiException.UnknownError()
)
}
is ApiResult.Loading -> {
_uiState.value = UiState.Loading // Emit loading state
}
}
}
}
}
}
FetchSessionDataUseCase.kt
class FetchSessionDataUseCase(private val repository: LivenessRepository) {
operator fun invoke(request: LivenessRequest): Flow {
return flow {
try {
emit(Loading())
when (val result = repository.getSessionData(request)) {
is Failure -> {
emit(Failure(ApiException.UnknownError()))
}
is Success -> {
emit(result.mapSuccess {
Success(value)
})
}
else -> {
emit(Failure(ApiException.UnknownError()))
}
}
} catch (e: HttpException) {
emit(
Failure(
ApiException.NetworkError(
e.localizedMessage ?: "An unexpected error occurred."
)
)
)
} catch (e: IOException) {
emit(Failure(ApiException.NetworkError("Couldn't reach server. Check your internet connection.")))
}
}.catch { e ->
emit(Failure(ApiException.UnknownError("An error occurred: ${e.localizedMessage ?: "Unknown error"}")))
}
}
}
LivenessRepository.kt
interface LivenessRepository {
suspend fun getSessionData(request: LivenessRequest): ApiResult
}
LivenessRepositoryImpl.kt
class LivenessRepositoryImpl(
private val dataSource: LivenessRemoteDataSourceImpl
) : LivenessRepository {
override suspend fun getSessionData(request: LivenessRequest): ApiResult {
val apiResult = performRequest(
request = {
dataSource.getSessionData(
request
)
},
transform = { apiResponse ->
apiResponse.toDomainModel()
},
)
return apiResult
}
}
Подробнее здесь: https://stackoverflow.com/questions/793 ... lure-calls
Мобильная версия