요즘은 학부생 때 막 제작했던 앱을 MVVM 구조로 리팩토링 하면서 시간을 보내고 있습니다.
기존에는 Firebase
데이터를 Sqlite DB
로 불러와서 Sqlite 쿼리를 사용하여 데이터 필터링을 하였습니다.
그러나 이는 상당히 비효율적이었습니다. Firebase의 onDataChanged
콜백을 전혀 활용하지 않고, 앱 실행과 동시에 모든 Firebase데이터를 SQLite DB에 때려박고 앱을 시작했으니까요. 당시엔 MVVM에 대해 알지도 못했기 때문에 UI컨트롤러에 모든 로직을 때려박는 미친짓을 감행했었습니다. 이 때문에 초기 앱이 실행될때, 데이터를 받아와서 SQLite에 때려박는데 수초의 시간을 기다려야 했습니다. (지금도 이 앱을 갤럭시 스토어에 배포중인데 사용자분들께 너무 죄송스럽네요ㅠㅠ)
따라서 SQLite를 제거하고, Firebase의 onDataChanged
를 이용하여 데이터가 갱신될 때 ViewModel의 LiveData를 갱신하는 로직으로 리팩토링 하였습니다. 그러나, SQLite의 편리했던 쿼리 기능이 없어지고 난 후에 어떻게 데이터를 날짜별로 필터링을 해야할까 대략 6시간 동안 고민하다가 로직을 겨우 짰네요.
이를 해결하기 위해 3개의 LiveData를 사용하였습니다.
var diaryData = MutableLiveData<MutableList<Diary>>()
var filteredList = MutableLiveData<MutableList<Diary>>()
var selectedDateTime = MutableLiveData<String>()
diaryData
: Firebase에서 실시간으로 갱신되는 전체 데이터
filteredList
: 날짜가 바뀜에 따라 새롭게 갱신되는 데이터
selectedDateTime
: 날짜가 변경됨을 알리기 위한 데이터
로직은 selectedDateTime
이 갱신될때마다 (날짜가 바뀔 때마다) filteredList
를 재 갱신 해주는 로직으로 작성하였습니다.
다음 코드는 filteredList
를 갱신하는 코드입니다. 왜 substring을 썼냐면, date의 날짜 포맷이 yyyy-MM-dd(HH:mm:ss) 형태고, selectedDateTime
의 날짜 포맷은 yyyy-MM-dd이기 때문에 filter 함수의 조건에 부합시키기 위해 가공했습니다.
fun setFilter() {
filteredList.value = diaryData.value?.filter {
it.date.isNotEmpty() && it.date.substring(0, 10) == selectedDateTime.value
}?.toMutableList()
}
따라서 이제 해당 프래그먼트로 가서 라이브 데이터들을 관찰 후 데이터 갱신이 이루어질때 알맞은 로직을 넣어주면 됩니다.
날짜가 바뀌면, filteredList
를 재갱신해주고, filteredList
가 바뀌면 리사이클러뷰를 재 갱신 해주면 됩니다.
viewModel.selectedDateTime.observe(viewLifecycleOwner) {
viewModel.setFilter()
}
viewModel.filteredList.observe(viewLifecycleOwner) {
diaryAdapter.differ.submitList(it)
}
만약 검색 필터링을 구현하고 싶다면 EditText의 addTextChangedListener
를 사용하여 edittext의 변경이 이루어질 때마다 setFilter()를 호출하면 되겠습니다. 다만 이는 데이터를 빠르게 입력할 수록 한꺼번에 많은 연산이 들어가기 때문에 코루틴을 사용하여 5초 정도의 딜레이를 주고 호출하는 것이 좋겠네요.