- 왼쪽 : 블로그 검색 데이터가 표시됩니다.
- 가운데 : 우리 자체 Firebase RDB를 사용하여 구현한 게시판이 표시됩니다.
- 오른쪽 : 두 데이터 소스에서 북마크된 아이템을 통합하여 앱 화면에 표시됩니다.
Problem
1. 데이터 관리를 Remote DataSource -Remote Repository - Domain Repository - Domain UseCase - ViewMode&LiveData로 하고 있습니다.
- 이는 MVVM아키텍처의 일부로써 데이터를 효과적으로 관리하고 비지니스 로직과 분리하여 코드를 간결하
고 직관적으로 보여주기 때문에 이해하기 쉽습니다.
2. 리사이클러뷰의 리스트어댑터에 넣어주기 위해서 데이터를 통합 했습니다.
3. 통합하는 과정에서 Remote DataSource를 통채로 뜯어 고칠 것인지, 파이어베이스 RDB 데이터 구성을 다 뜯어 고칠것인지, 데이터 클래스를 통합을 할 것인지 등등 많은 고민이 있었습니다.
4. 그 중 데이터 클래스를 통합하기 위해 공용 인터페이스를 생성하고, 각각의 데이터클래스에 인터페이스 반환타입을 추가 하는 방식을 선택 했습니다.
▶ 그 결과 ViewModel에서 데이터는 통합되서 정상적으로 로그에 찍히는데 MyPage화면에서 데이터가 갱신이 되지않는 이슈가 발생했습니다.
▼ ViewModel ▼
class BookmarkPageViewModel(
private val getFirebaseScrapData: GetFirebaseScrapData,
//Firebase RDB데이터에서 블로그 데이터를 받아오는 use케이스 입니다.
private val getFirebaseBoardDataFromScrapRepo: GetFirebaseBoardDataUseCase,
//Firebase RDB데이터에서 게시판 데이터를 받아오는 use케이스 입니다.
private val saveFirebaseBoardDataUseCase: SaveFirebaseBoardDataUseCase,
//Firebase RDB데이터에 업데이트된 데이터를 저장하는 use케이스 입니다.
private val getFirebaseBoardKeyDataFromScrapRepo: GetFirebaseBookMarkData
//Firebase RDB데이터에 북마크 했던 게시판 item을 식별하는 key를 저장하는 use케이스 입니다.
) : ViewModel() {
private val _mypageScraps: MutableLiveData<List<ScrapEntity?>> = MutableLiveData()
val myPageList get() = _mypageScraps
private val _mypageBoard: MutableLiveData<List<CommunityModelEntity?>> = MutableLiveData()
val mypageBoard get() = _mypageBoard
private val _likeKeyResults: MutableLiveData<List<KeyModelEntity?>> = MutableLiveData()
private val _boardKey: MutableLiveData<List<BoardKeyModelEntity?>> = MutableLiveData()
val _totalMyPage: MutableLiveData<List<ScrapInterface?>> = MutableLiveData()
val totalMyPage get() = _totalMyPage
fun updateScrapData(context: Context) = viewModelScope.launch {
// 블로그 데이터를 실질적으로 관리하는 메서드 입니다.
kotlin.runCatching {
val uid = SharedPreferences.getUid(context)
getFirebaseScrapData.invoke(uid, _mypageScraps)
//uid와 블로그 라이브데이터를 이용해서 use케이스를 호출하므로써 RDB의 블로그 데이터를 관리합니다.
}
}
fun updateBoardData(uid: String) = viewModelScope.launch {
// 게시판 데이터를 실질적으로 관리하는 메서드 입니다.
kotlin.runCatching {
getFirebaseBoardDataFromScrapRepo.invoke(
//uid, 게시판 라이브데이터, 게시판데이터를 식별하는 라이브데이터를 이용해서 use케이스를 호출하므로써 RDB의 게시판 데이터를 관리합니다.
uid,
_mypageBoard,
_likeKeyResults
)
}
}
fun getBoardKeyData(uid: String) {
//게시판 아이템을 북마크했는지 식별할 수 있는 키를 실질적으로 관리하는 메서드 입니다.
getFirebaseBoardKeyDataFromScrapRepo(uid, _boardKey)
//uid, 게시판 아이템을 북마크를 식별하는 라이브데이터를 이용해서 use케이스를 호출하므로써 RDB의 북마크키를 관리합니다.
}
fun mergeScrapAndBoardData() {
// 리사이클러뷰에 넣어주기위해 북마크된 블로그 아이템과 게시판 아이템을 통합하여 관리하는 메서드 입니다.
val scraps = _mypageScraps.value ?: emptyList()
val boardData = _mypageBoard.value ?: emptyList()
val boardKey = _boardKey.value ?: emptyList()
boardKey.forEach { boardKeyItem ->
val selectItem = boardData.find { it?.key == boardKeyItem?.key }
//내가 선택한 게시판 아이템이 북마크된 아이템인지 북마크 키를 이용해서 식별합니다.
if (selectItem != null) {
selectItem.boardIsLike = boardKeyItem!!.myBoardIsLike
//내가 선택한 게시판 아이템이 북마크했던 아이템으로 식별이 되었다면 북마크 키에 저장된 데이터로 업데이트 시켜줍니다.
}
}
val bookMarkBoardData = boardData.filter { it?.boardIsLike == true }
// 식별되어 업데이트된 게시판 아이템중에 true인것들이 북마크 했던 아이템이므로 true인 아이템만 필터해줍니다.
_totalMyPage.value = scraps + bookMarkBoardData
//위에서 식별하고 업데이트된 북마크 (게시판아이템과 블로그아이템)을 합쳐줍니다.
}
fun saveBoardFirebase(model: CommunityModelEntity) {
// 게시판 아이템을 클릭했을때 조회수를 증가시켜주는 메서드 입니다.
val currentView = model.views?.toIntOrNull() ?: 0
//게시판 아이템의 현재 조회수를 체크하고 만약 null값이면 0을 반환합니다. int형으로 변환해주는 이유는 클릭할 떄 마다 조회수를 증가시키는 연산을 하기 때문입니다.
val newViews = currentView + 1
//게시판 아이템을 클릭했을때 현재 조회수가 1씩 증가합니다.
model.views = newViews.toString()
//RDB에 저장하기위해 다시 String타입으로 형변환 해줍니다.
saveFirebaseBoardDataUseCase(model,_mypageBoard)
// 내가 선택한 model과 게시판 라이브데이터를 이용해서 usecase를 호출하므로써 업데이트된 조회수를 RDB에 저장합니다.
updateBoardData(model.id)
//조회수가 증가해서 업데이트된 RDB의 게시판 데이터를 호출합니다.
}
}
Solution
1. 화면이 갱신 되지 않는 문제를 해결하기 위해서 뷰모델의 "mergeScrapAndBoardData()"함수에서 로그를 확인 했습니다. 그 결과 "_totalMyPage.value" 값이 정상적으로 찍히는것을 확인했습니다. (RDB데이터를 받아오는 과정은 문제없음)
2. 뷰모델을 사용하는 프래그먼트에서 ergeScrapAndBoardData()를 호출하는 함수에서 로그를 찍어 보았는데 로그가 빈값이 찍히고, 다른탭을 눌렀다가 와야 정상적으로 찍히는 것을 확인할 수 있었습니다. (프래그먼트에서 라이브데이터를 관찰하는데 빈로그가 찍히는것을보면 데이터 변화를 감지 하지 못한다는것을 확인)
3. 위 두 과정으로 생성주기 때문은 아닌것을 확인했습니다. 왜냐하면 어쨋든 빈값이 로그찍히는것은 함수가 호출 된다는 의미이기때문에 해당 프래그먼트의 생명주기가 정상이라는것을 알 수 있기 때문입니다.
4. 그런데 이상한건 다른탭을 두번눌렀다가 MyPage탭을 눌러야 갱신이 된다는 점입니다.
5. 간단히 말하면 뷰모델에서 두개의 라이브데이터를 통합한 로그는 정상적으로 찍히지만, MyPage 화면의 갱신이 다른탭을 두번눌렀다가 돌아와야 갱신이 된다는 점입니다.
6. 이로부터 라이브데이터가 통합은 정상적으로 되지만, 통합된 라이브데이터를 관찰하는 프래그먼트에서 블로그북마크 데이터와 게시판 북마크 데이터를 불러오기전에 통합을 수행하고 있기 때문에 빈 값으로 호출되는 것을 확인했습니다.
▶ 뷰모델에서 RDB의 게시판데이터와 블로그 데이터를 불러오는데 문제가 없습니다.
▶ 빈값이 로그가 찍히므로 생명주기와는 관련없습니다.
▶결론적으로 블로그 데이터와 RDB게시판 데이터를 불러오기도전에 합치고있으니 문제가 있는것을 알 수 있었습니다.
Complete
▼ Fragment ▼
private fun initViewModel() {
with(viewModel) {
totalMyPage.observe(viewLifecycleOwner) {// 북마크 된 블로그데이터와 게시판데이터를 통합한 데이터를 관찰합니다.
bookmarkAdapter.submitList(it) //변화가 감지된다면 업데이트된 통합데이터를 어댑터에 넣어줍니다.
Log.d("TripMates", "List:${it}")
}
myPageList.observe(viewLifecycleOwner) {//북마크된 블로그 데이터의 변화를 관찰합니다.
Log.d("TripMates", "List:${it}")
mergeScrapAndBoardData() //변화가 감지된다면 통합하는 함수를 호출합니다.
}
mypageBoard.observe(viewLifecycleOwner) {//북마크된 게시판 데이터의 변화를 관찰합니다.
Log.d("TripMates", "board: ${it}")
mergeScrapAndBoardData() //변화가 감지된다면 통합하는 함수를 호출합니다.
}
}
}
북마크 된 블로그 데이터와 RDB게시판을 불러오는 라이브데이터를 각각 관찰하고 데이터를 불러올때마다 라이브데이터를 통합하는 함수를 호출시켜서 해결했습니다.
썸네일 출처
'TIL, WIL(일기)' 카테고리의 다른 글
231101 중간 발표 (0) | 2023.11.01 |
---|---|
231031 [Trouble Shooting] RDB 응답데이터 갱신 이슈 (0) | 2023.10.31 |
231024 [Trouble Shooting] 프래그먼트 갱신 이슈 (0) | 2023.10.24 |
231019 (4)구글로그인 연동하기(저장 : Realtime Database) (0) | 2023.10.19 |
231015 (1)구글로그인 연동하기(SHA-1인증서) (0) | 2023.10.16 |