[안드로이드] 화면 변경 시 앱이 리프레쉬 되는 문제 해결

0
post-thumbnail

잡담

지난해 갤럭시 스토어 앱 출시후 받았던 검토 리포트를 다시 한번 읽어보았습니다.

총 두가지의 issue를 보고 받았는데요,

첫 번째 페이스북 로그인 이슈는 페이스북 개발자 사이트에서 인증 SDK를 최신 버전으로 설치하고, 앱 모드를 라이브 모드로 변경하여 해결하였습니다.

문제는 두 번째 이슈였습니다. 폴더블 디바이스에서 폴딩/언폴딩 작업. 즉, 플렉서블 모드를 사용하거나, 앱을 멀티 윈도우로 띄울 때 앱이 리프레쉬 현상이 발생한다고 보고받았습니다. 받았을 당시에는 안드로이드에 대해 잘 알지 못했던지라.. 어떻게 해결해야할지 몰라 방치하고만 있었는데요, 최근 MVVM을 공부하다가 바로 유레카!를 외쳤습니다.

이전에도 말씀드렸다시피, 이전까지 만든 제 앱은 한 UI 컴포넌트에 모든 기능을 때려박아서 어찌저찌 돌아가기만 했던 앱을 개발하고 배포했었습니다. 당연히 화면 회전과 같은 구성요소의 변경이 이루어지면 리프레시가 일어나는건 당연했습니다.

따라서 앱을 MVVM 구조로 리팩토링을 시도하였고 ViewModel의 LiveData를 모든 UI구성요소와 공유하며, 앱 구성요소 변경시에도 작업하던 UI데이터가 유지되도록 재작성하였습니다.

LiveData

모든 UI데이터를 유지하기 위해 사용했던 LiveData는 아래 코드와 같습니다.

private var _diaryData = MutableLiveData<MutableList<Diary>>()
private var _filteredList = MutableLiveData<MutableList<Diary>>()
private var _selectedDateTime = MutableLiveData<String>()
private var _userInfo = MutableLiveData<UserInfo>()
private var _countDiaryContents = MutableLiveData<HashMap<String, Int>>()
private var _currentCalendarDate = MutableLiveData<Date>()

val diaryData get() = getData()
val filteredList get() = _filteredList
val selectedDateTime get() = _selectedDateTime
val userInfo get() = _userInfo
val countDiaryContents get() = _countDiaryContents
val currentCalendarDate get() = _currentCalendarDate

시리즈 첫장에서도 설명 드렸듯이, LiveData 프로퍼티를 위와 같이 노출 하는 것은 결국 외부에서 Immutable 하게 사용하도록 제약을 주기 위함입니다.

이를 필요로 하는 UI 컴포넌트에 관찰자(Observer)를 두어 데이터를 실시간 갱신시키며 UI데이터를 유지했습니다.

관찰자 사용

다음은 각각의 UI 구성요소에 관찰자를 두고 LiveData가 변경되면 UI를 갱신할 수 있도록 코드를 작성했습니다. 물론, 화면 구성요소가 변경될 때는 최근까지 갱신되었던 LiveData를 UI에 자동으로 갱신해줍니다. 다음은 캘린더 프래그먼트에서의 관찰자 사용 코드입니다.

viewModel.currentCalendarDate.observe(viewLifecycleOwner) {
	// 보고있는 달력의 날짜가 변경되면 갱신한다.
    binding.calendarTitle.text = simpleDateFormat.format(it)
    binding.tvSelDate.text = DateFormat.format(it)
    binding.compactcalendarView.setCurrentDate(it)
}

viewModel.countDiaryContents.observe(viewLifecycleOwner) {
	// 일기 데이터가 추가되면 달력에 개수를 표시한다.
    Setdate(it, viewModel.currentCalendarDate.value ?: myCalendar.time, false)
    calendarlistener(it)
}

0개의 댓글