Gemini_로직_수정_과정 - boostcampwm-2024/and04-Nature-Album GitHub Wiki
✅ 진행한 기능
- Gemini 로딩 처리
- Gemini 로직 변경
💡문제 해결 과정 기록
사진 촬영 후 저장 화면으로 이동하면, 현재 로직에서는 Gemini API의 라벨링 응답이 올 때까지 로딩 바를 표시하며 대기하고 있다.
그러나 Gemini API의 응답 속도가 느릴 경우 최대 10초까지 걸리는 상황이 발생하기도 하여, 사용자가 이러한 대기 시간을 모두 견디는 것은 바람직하지 않다는 의견이 제기되었기에 이에 따라 로직을 개선하고자 한다.
우선 사진을 찍고 사진 저장화면(SavePhotoScreen
) 에서 Gemini API를 호출하는 것이 아니라 라벨 선택 화면(LabelSearchScreen
) 에서 처리하도록 수정하고자 했다.
💥 Cannot be found in the navigation graph
문제 상황
AI 라벨링 처리를 라벨 선택 화면에서 처리하기 위하여 SavePhotoScreen에서 LabelSearchScreen으로 사진 Uri를 전송해야 했다. 하지만 그 과정에서 위와 같은 에러가 발생했다.
문제 해결 과정
Compose Navigation Argument로 url 전달하기
Stack Overflow Passing URL as a parameter to Jetpack Compose Navigation
위의 블로그 글을 보고 해결할 수 있었다.
즉, Navigation 과정에서 Uri를 넘기기 위해서는 인코딩 과정이 필요하다는 것이다.
위의 블로그 글의 일부를 참고하여 해결할 수 있었다.
val encodedUrl = URLEncoder.encode(uri, StandardCharsets.UTF_8.toString())
navController.navigate("${NavigateDestination.SearchLabel.route}/$encodedUrl")
💥 Something unexpected happened.
LabelSearchScreen에서 AI의 답변을 받기도 전에 사용자가 직접 라벨을 입력하거나 취소등의 이유로 다시 SavePhotoScreen으로 이동하게 된다면 실행중이던 코루틴이 Cancel되면서 발생한 오류이다.
우선은 try - catch
를 통해 에러가 발생하면 UiState.Error
에 에러 메세지를 담아두는 방식으로 처리했는데, 후에 더 안전하게 코루틴을 cancel하는 방법을 생각해야할 것 같다.
https://github.com/user-attachments/assets/43ae9f7a-c202-4abb-99f7-29983eb0ae4d
여기서 고민되는 부분이 있었다.
우선 사용자가 찍은 사진에 대해서 라벨 선택 화면으로 이동할 때마다 AI에게 라벨링 요청하게 된다.
즉, 사용자가 라벨 선택 화면을 여러번 전환한다면 여러번 호출하게 되는 것이다.
이 부분에서는 혼자 고민하는 것 보다 팀원들과 함께 방향을 잡는 것이 더 낫겠다는 생각이 들었고 아래와 같은 조언을 얻었다.
또 다른 팀원은 아래와 같은 로직을 추천해줬다.
- SavePhotoScreen에서는 로딩작업을 하지 않고 요청작업 진행
- AI 추천 라벨은 LabelSerachScreen에서 가져올 수 있음.
- 만약 로딩 중 이라면 LabelSearchScreen에서 로딩 처리
즉, SavePhotoScreen에서는 작업을 계속 진행하고, 그 진행된 작업에 대한 결과물은 다른 화면인 LabelSearchScreen에서 받아와 처리하는 것이다.
이것이 가능하게 하려면 SavePhotoViewModel
을 두 Screen에서 공유해야하는 것이다.
❓어떻게 뷰모델을 공유할 수 있을까?
[Compose] hiltViewModel()과 viewModel() 차이
정리하면 Screen에서 인스턴스를 생성하던 로직을 하나 더 윗 단계인 NatureAlbumApp
에서 생성하도록 변경하는 것이다.
composable(NavigateDestination.SearchLabel.route) { backStackEntry ->
val viewmodel = remember(backStackEntry) {
navController.getBackStackEntry(NavigateDestination.SavePhoto.route)
}
LabelSearchScreen(
onSelected = { label ->
selectedLabel = label
navController.popBackStack()
},
savePhotoViewModel = hiltViewModel(viewmodel),
)
}
navController
가 getBackStackEntry
를 호출하고, 내가 지정한 route에 대한 NavBackStackEntry
를 받고, 거기서 NavBackStackEntry
를 이용해서 ViewModelFactory
로 내가 원하는 뷰 모델을 가져오는 것.
[자세한 건 추후 학습 후 문서화하여 링크 올릴 예정]