개발/최적화
뷰모델 중복 이슈 해결
이도일
2023. 5. 3. 17:00
https://medium.com/prnd/mvvm의-viewmodel에서-이벤트를-처리하는-방법-6가지-31bb183a88ce
뷰모델의 문제점
- 뷰모델은 뷰가 변경되면 가장 최근 값들로 .observe를 해주는데 , 중요한건 이게 값이 바뀌지 않아도 최근 값을 걍 들고오기때문에…..
- 토스트를 띄운 후 나갔다가 다시 fragment 갱신 → 토스트 재생성과 같은 중복 이슈가 발생하게 된다.
해결 방안
- 사실 이 문제는 아주 흔한 것이라서 구글에서 이미 해결책을 내놨다.
- 나는 SharedFlow + Sealed class + Lifecycle 를 사용했다.
SharedFlow
private val _eventflow = MutableSharedFlow<Resource<Event>>()
val eventflow: MutableSharedFlow<Resource<Event>> = _eventflow
Event emit
private fun event(event: Resource<Event>) {
launchViewModelScope {
_eventflow.emit(event)
}
}
Event Data Class
sealed class Event {
data class deleteTimeTable (val value: BaseServiceModel) : Event()
data class getTimeTableList (val value: TimeTable) : Event()
data class getTimeTableInfo (val value: TimeTableInfo) : Event()
data class getSubjectList (val value: TimeTableSubject) : Event()
data class insertSubjectByOne (val value: BaseServiceModel) : Event()
data class deleteSubject (val value: BaseServiceModel) : Event()
data class saveTimeTableInfo2( val value: BaseServiceModel) : Event()
}
Handle Event func (in Activity)
private fun handleEvent(event: Resource<Event>) {
when (event.status) {
Status.LOADING -> {
ProgressUtil.progressOn(requireActivity())
}
Status.SUCCESS -> {
ProgressUtil.progressOff()
when (event.data) {
is Event.getTimeTableList -> {
event.data.value?.let { data ->
titleArrayList.clear()
setSelectedPosition = 0
if (data.List.isNotEmpty()) {
binding.frameLayout.visibility = View.VISIBLE
binding.topLayout.visibility = View.VISIBLE
binding.subjectLayout.visibility = View.VISIBLE
binding.emptyText.visibility = View.GONE
data.List.forEach { tableData ->
titleArrayList.add(tableData.TTM_Title)
}
if (titleArrayList.size == 1) {
binding.spinner.visibility = View.GONE
binding.calArrow.visibility = View.GONE
} else {
binding.spinner.visibility = View.VISIBLE
binding.calArrow.visibility = View.VISIBLE
}
// Dlog.d("timetable titleArrayList = $titleArrayList")
// binding.timeTableTitle.text = titleArrayList[setSelectedPosition]
timeTableMasSeq = data.List[setSelectedPosition].TTM_SEQ
viewModel.getSubjectList()
//viewModel.getTimeTableInfo(data.List[0].TTM_SEQ)
spdSeq = SharedPreference.getTimetableSpdSeqPref(requireContext())
// Dlog.d("timetable spdSeq = $spdSeq changeTimeTable")
if (spdSeq != "0") {
binding.timeTableTitle.postDelayed({
getFromData()
}, 300)
} else {
binding.timeTableTitle.text =
titleArrayList[setSelectedPosition]
}
if (binding.timeTableRecyclerview.visibility == View.INVISIBLE) {
binding.timeTableTitle.postDelayed({
binding.timeTableRecyclerview.visibility = View.VISIBLE
binding.loading.visibility = View.GONE
}, 750)
}
} else {
binding.frameLayout.visibility = View.GONE
binding.topLayout.visibility = View.GONE
binding.subjectLayout.visibility = View.GONE
binding.emptyText.visibility = View.VISIBLE
// binding.timeTableRecyclerview.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
binding.timeTableRecyclerview.visibility = View.VISIBLE
binding.loading.visibility = View.GONE
}
spinnerAdapter.setItem(titleArrayList)
spinnerAdapter.setSelectedPosition(setSelectedPosition)
spinnerAdapter.notifyDataSetChanged()
}
}
is Event.deleteTimeTable -> {
event.data.value?.let { data ->
if (data.SuccessYN == ResultCode.RESULT_YES) {
viewModel.getTimeTableList()
ToastUtil.showShort(data.Message)
}
}
}
is Event.insertSubjectByOne -> {
event.data.value?.let { data ->
ToastUtil.showShort(data.Message)
if (data.SuccessYN == ResultCode.RESULT_YES) {
dialogAddSubject.dismiss()
viewModel.getSubjectList()
}
}
}
is Event.deleteSubject -> {
ProgressUtil.progressOff()
event.data.value?.let { data ->
if (data.SuccessYN == ResultCode.RESULT_YES) {
ToastUtil.showShort(data.Message)
dialogEditSubject.dismiss()
viewModel.getTimeTableInfo(timeTableMasSeq)
}
}
}
is Event.getTimeTableInfo -> {
event.data.value.let {
it
//viewModel.getSubjectList()
setTimeTable(it)
}
}
is Event.getSubjectList -> {
event.data?.value.List?.let { data ->
setSubject(data as ArrayList<TimeTableSubjectData>)
viewModel.getTimeTableInfo(timeTableMasSeq)
}
}
is Event.saveTimeTableInfo2 -> {
event.data?.value.let { data ->
if (data.SuccessYN == ResultCode.RESULT_YES) {
ToastUtil.showShort(data.Message)
viewModel.getTimeTableInfo(timeTableMasSeq)
}
}
}
}
}
Status.ERROR -> {
}
}
}
Collect(in Activity)
repeatOnStarted {
viewModel.eventflow.collect { event -> handleEvent(event) }
}