-
Notifications
You must be signed in to change notification settings - Fork 0
[refactor] #85 랜덤포즈 중복 확인 위치 변경 #88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package com.neki.android.core.common.exception | ||
|
|
||
| class RandomPoseRetryExhaustedException( | ||
| message: String, | ||
| ) : RuntimeException(message) |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,9 +3,9 @@ package com.neki.android.feature.pose.impl.random | |||||||||||||||||||||||||||||||||||||||
| import androidx.lifecycle.ViewModel | ||||||||||||||||||||||||||||||||||||||||
| import androidx.lifecycle.viewModelScope | ||||||||||||||||||||||||||||||||||||||||
| import com.neki.android.core.common.coroutine.di.ApplicationScope | ||||||||||||||||||||||||||||||||||||||||
| import com.neki.android.core.common.exception.RandomPoseRetryExhaustedException | ||||||||||||||||||||||||||||||||||||||||
| import com.neki.android.core.dataapi.repository.PoseRepository | ||||||||||||||||||||||||||||||||||||||||
| import com.neki.android.core.model.PeopleCount | ||||||||||||||||||||||||||||||||||||||||
| import com.neki.android.core.model.Pose | ||||||||||||||||||||||||||||||||||||||||
| import com.neki.android.core.ui.MviIntentStore | ||||||||||||||||||||||||||||||||||||||||
| import com.neki.android.core.ui.mviIntentStore | ||||||||||||||||||||||||||||||||||||||||
| import com.neki.android.feature.pose.impl.const.PoseConst | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -152,21 +152,16 @@ internal class RandomPoseViewModel @AssistedInject constructor( | |||||||||||||||||||||||||||||||||||||||
| // 여분 포즈가 POSE_PREFETCH_THRESHOLD 이하이면 다음 포즈 미리 캐싱 | ||||||||||||||||||||||||||||||||||||||||
| if (state.poseList.lastIndex - nextIndex < PoseConst.POSE_PREFETCH_THRESHOLD) { | ||||||||||||||||||||||||||||||||||||||||
| viewModelScope.launch { | ||||||||||||||||||||||||||||||||||||||||
| when (val result = fetchRandomPose(poseList = state.poseList)) { | ||||||||||||||||||||||||||||||||||||||||
| is FetchPoseResult.Success -> reduce { | ||||||||||||||||||||||||||||||||||||||||
| copy( | ||||||||||||||||||||||||||||||||||||||||
| poseList = (poseList + result.pose).toImmutableList(), | ||||||||||||||||||||||||||||||||||||||||
| committedScraps = committedScraps + (result.pose.id to result.pose.isScrapped), | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| is FetchPoseResult.Duplicated -> | ||||||||||||||||||||||||||||||||||||||||
| Timber.d("프리페치 생략: ${result.tryCount}회 시도 후 중복 포즈") | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| is FetchPoseResult.Failure -> { | ||||||||||||||||||||||||||||||||||||||||
| Timber.e(result.throwable) | ||||||||||||||||||||||||||||||||||||||||
| postSideEffect(RandomPoseEffect.ShowToast("포즈를 불러오는데 실패했어요")) | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| poseRepository.getSingleRandomPose( | ||||||||||||||||||||||||||||||||||||||||
| headCount = peopleCount, | ||||||||||||||||||||||||||||||||||||||||
| excludeIds = state.randomPoseIds, | ||||||||||||||||||||||||||||||||||||||||
| maxRetry = PoseConst.MAXIMUM_RANDOM_POSE_RETRY_COUNT, | ||||||||||||||||||||||||||||||||||||||||
| ).onSuccess { pose -> | ||||||||||||||||||||||||||||||||||||||||
| reduce { copy(poseList = (poseList + pose).toImmutableList()) } | ||||||||||||||||||||||||||||||||||||||||
| }.onFailure { error -> | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+155
to
+161
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefetch로 추가된 포즈의 Line 160에서 새 포즈를 🐛 committedScraps 업데이트 추가 ).onSuccess { pose ->
- reduce { copy(poseList = (poseList + pose).toImmutableList()) }
+ reduce {
+ copy(
+ poseList = (poseList + pose).toImmutableList(),
+ committedScraps = committedScraps + (pose.id to pose.isScrapped),
+ )
+ }
}.onFailure { error ->📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||
| if (error is RandomPoseRetryExhaustedException) | ||||||||||||||||||||||||||||||||||||||||
| Timber.e(error, "중복 포즈") | ||||||||||||||||||||||||||||||||||||||||
| else Timber.e(error) | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -179,73 +174,31 @@ internal class RandomPoseViewModel @AssistedInject constructor( | |||||||||||||||||||||||||||||||||||||||
| viewModelScope.launch { | ||||||||||||||||||||||||||||||||||||||||
| reduce { copy(isLoading = true) } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| val poses = mutableListOf<Pose>() | ||||||||||||||||||||||||||||||||||||||||
| var totalFallbackCount = 0 | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // 초기에 INITIAL_POSE_LOAD_COUNT개 로드 | ||||||||||||||||||||||||||||||||||||||||
| while ( | ||||||||||||||||||||||||||||||||||||||||
| poses.size < PoseConst.INITIAL_POSE_LOAD_COUNT && | ||||||||||||||||||||||||||||||||||||||||
| totalFallbackCount < PoseConst.MAXIMUM_RANDOM_POSE_FALLBACK_COUNT | ||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||
| val result = fetchRandomPose( | ||||||||||||||||||||||||||||||||||||||||
| poseList = poses, | ||||||||||||||||||||||||||||||||||||||||
| maxFallbackCount = PoseConst.MAXIMUM_RANDOM_POSE_FALLBACK_COUNT - totalFallbackCount, | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| totalFallbackCount += result.tryCount | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| when (result) { | ||||||||||||||||||||||||||||||||||||||||
| is FetchPoseResult.Success -> poses.add(result.pose) | ||||||||||||||||||||||||||||||||||||||||
| is FetchPoseResult.Failure -> { | ||||||||||||||||||||||||||||||||||||||||
| Timber.e(result.throwable) | ||||||||||||||||||||||||||||||||||||||||
| postSideEffect(RandomPoseEffect.ShowToast("포즈를 불러오는데 실패했어요")) | ||||||||||||||||||||||||||||||||||||||||
| break | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| is FetchPoseResult.Duplicated -> | ||||||||||||||||||||||||||||||||||||||||
| Timber.d("초기 로드: ${result.tryCount}회 시도 후 중복 포즈") | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if (poses.isNotEmpty()) { | ||||||||||||||||||||||||||||||||||||||||
| poseRepository.getMultipleRandomPose( | ||||||||||||||||||||||||||||||||||||||||
| headCount = peopleCount, | ||||||||||||||||||||||||||||||||||||||||
| excludeIds = emptySet(), | ||||||||||||||||||||||||||||||||||||||||
| poseSize = PoseConst.INITIAL_POSE_LOAD_COUNT, | ||||||||||||||||||||||||||||||||||||||||
| maxRetry = PoseConst.MAXIMUM_RANDOM_POSE_RETRY_COUNT, | ||||||||||||||||||||||||||||||||||||||||
| ).onSuccess { data -> | ||||||||||||||||||||||||||||||||||||||||
| reduce { | ||||||||||||||||||||||||||||||||||||||||
| copy( | ||||||||||||||||||||||||||||||||||||||||
| isLoading = false, | ||||||||||||||||||||||||||||||||||||||||
| poseList = poses.toImmutableList(), | ||||||||||||||||||||||||||||||||||||||||
| committedScraps = poses.associate { it.id to it.isScrapped }, | ||||||||||||||||||||||||||||||||||||||||
| poseList = data.toImmutableList(), | ||||||||||||||||||||||||||||||||||||||||
| committedScraps = data.associate { it.id to it.isScrapped }, | ||||||||||||||||||||||||||||||||||||||||
| currentIndex = 0, | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||
| }.onFailure { error -> | ||||||||||||||||||||||||||||||||||||||||
| Timber.e(error) | ||||||||||||||||||||||||||||||||||||||||
| reduce { copy(isLoading = false) } | ||||||||||||||||||||||||||||||||||||||||
| postSideEffect(RandomPoseEffect.ShowToast("포즈를 불러오는데 실패했어요")) | ||||||||||||||||||||||||||||||||||||||||
| if (error is RandomPoseRetryExhaustedException) | ||||||||||||||||||||||||||||||||||||||||
| Timber.e(error, "중복 포즈") | ||||||||||||||||||||||||||||||||||||||||
| else Timber.e(error) | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+192
to
198
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Line 193에서 🐛 중복 로깅 수정 }.onFailure { error ->
- Timber.e(error)
reduce { copy(isLoading = false) }
if (error is RandomPoseRetryExhaustedException)
Timber.e(error, "중복 포즈")
else Timber.e(error)
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| private suspend fun fetchRandomPose( | ||||||||||||||||||||||||||||||||||||||||
| poseList: List<Pose>, | ||||||||||||||||||||||||||||||||||||||||
| maxFallbackCount: Int = PoseConst.MAXIMUM_RANDOM_POSE_FALLBACK_COUNT, | ||||||||||||||||||||||||||||||||||||||||
| ): FetchPoseResult { | ||||||||||||||||||||||||||||||||||||||||
| var tryCount = 0 | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| while (tryCount < maxFallbackCount) { | ||||||||||||||||||||||||||||||||||||||||
| tryCount++ | ||||||||||||||||||||||||||||||||||||||||
| poseRepository.getRandomPose(headCount = peopleCount) | ||||||||||||||||||||||||||||||||||||||||
| .onSuccess { pose -> | ||||||||||||||||||||||||||||||||||||||||
| if (poseList.none { it.id == pose.id }) { | ||||||||||||||||||||||||||||||||||||||||
| return FetchPoseResult.Success(tryCount, pose) | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| .onFailure { error -> | ||||||||||||||||||||||||||||||||||||||||
| Timber.e(error) | ||||||||||||||||||||||||||||||||||||||||
| return FetchPoseResult.Failure(tryCount, error) | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return FetchPoseResult.Duplicated(tryCount) | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| override fun onCleared() { | ||||||||||||||||||||||||||||||||||||||||
| super.onCleared() | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getMultipleRandomPose가poseSize보다 적은 결과를 조용히 반환할 수 있습니다.retryCount가maxRetry에 도달하면 while 루프가 종료되지만,result가 비어있지 않으면 (1개 이상) 예외 없이 부분 결과를 반환합니다. 예를 들어poseSize=4,maxRetry=7일 때 2개만 수집하고 7회 중복이 발생하면 2개짜리 리스트가 반환됩니다.호출부(
fetchInitialPoses)에서는 반환된 리스트를 그대로poseList에 설정하므로, 요청한 개수보다 적은 포즈가 표시될 수 있습니다.의도된 동작이라면 주석으로 명시하고, 그렇지 않다면
result.size < poseSize일 때도 예외를 던지거나 호출부에서 처리하는 것을 권장합니다.💡 부분 결과도 예외로 처리하는 경우
🤖 Prompt for AI Agents