반응형
Notice
Recent Posts
Recent Comments
Link
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Archives
Today
Total
관리 메뉴

코딩하기 좋은날

안드로이드 ViewModels 과 LiveData 패턴 및 안티패턴 (MVVM 패턴) 본문

Android

안드로이드 ViewModels 과 LiveData 패턴 및 안티패턴 (MVVM 패턴)

huiung 2020. 10. 24. 22:25
반응형

📝아키텍처 패턴을 왜적용 해야 하는가? 

 

- 글을 들어가기에 앞서 아키텍처 패턴을 적용해야 하는 이유를 말해보려고 합니다. 아키텍처 패턴을 신경쓰면서 코드를 작성하는 것은 쉬운일이 아닙니다. 그러나 코드가 방대해질수록 마구잡이로 작성된 프로젝트를 수정하기란 정말 어렵습니다. 실제로 프로그램의 라이프 싸이클을 본다면 단순 개발이 차지하는 비율은 어느정도 안됩니다. (유지보수가 아주 많은 부분을 차지하죠.) 물론 저는 그런 프로그램을 개발한 뒤 유지보수를 해본 경험이 없지만.. 당장 제프로젝트의 코드를 수정 할 때도 마구잡이로 짜 놓은 프로젝트는 답이 없다라는 것을 종종 느낍니다. 아키텍처 패턴을 적용하고 기타 여러 도구들을 이용함으로써 우아하고 클린한 프로그램으로 변하는 것을 몸소 느낄 수 있을거라 생각합니다!!

 

 

 

아키텍처 패턴 중 하나인 MVVM 패턴을 적용해보려고 시도하던 중 ViewModels 과 LiveData를 어떤식으로 써야하고 어떤식으로 쓰지 말아야 하는지에 대한 정말 좋은 글이 있어서 읽어보면서 정리를 해보려고 합니다. (사실상 번역해서 요약한것에 불과합니다..)

 

https://medium.com/androiddevelopers/viewmodels-and-livedata-patterns-antipatterns-21efaef74a54

 

ViewModels and LiveData: Patterns + AntiPatterns

A collection of patterns and recommendations that we’ve been collecting since we released the first alpha version of the Architecture Components.

medium.com

실제 구글 개발자분 께서 쓰신 글이므로 꽤오래된 글이지만 좋은글이라고 생각합니다!! 그림은 모두 해당글에서 가져온것입니다.

 

위의 그림은 일반적으로 MVVM패턴을 얘기할 때 많이 보이는 구조입니다. ViewModel이 LiveData를 가지고 있고 View가 이를 observes 하고있습니다. ViewModel은 Repository를 통해 Data관련 작업을 처리하게 됩니다.

 

이상적으로 ViewModel은 Android에 대해서 아무것도 알지 못해야 합니다.

 

-> 테스트 용이 및 메모리 leak에대해 안전해집니다. (ViewModel은 View보다 lifecycle이 기므로 View에 대한 참조가 있으면 메모리 leak이 발생 할 수 있습니다.)

 

-> 일반적으로 rule of thumb에 의하면 Android에 대해서 아무것도 알지 못한다는 것은 ViewModel에서 import android.* 와 같은 코드가 없다는 것을 의미한다고 합니다. (android.arch.* 은 예외)

 

-> 이렇게 함으로써 다른 아키텍처 패턴에 비해 View와 ViewModel사이의 의존성이 줄어들 수 있습니다.

 


 

 

✅ 조건문, 반복문, 일반적인 Decisions와 같은 동작들은 ViewModel이나 다른 레이어에서 행해져야 한다고 합니다.

 

-> 이렇게 함으로써 Activity 나 Fragment는 unit Test를 하지 않아도 됩니다. (코드 또한 줄어듭니다.)

 

-> 제코드의 MainActivity에서 실제로 ViewModel의 LiveData들을 Observe하고 있는데 실제로 단순히 값만 변경 하는 경우는 DataBinding을 이용하여 변경해주므로 큰 문제가 없습니다.

 

-> 그러나 어떤 상태 변화를 감지하는 값들은 직접 Observe를 하고 그값의 변화에 따라(if) Toast를 띄운다던지와 같은 동작을 하고 있는데 이러한 경우 조건문을 Activity에서 안쓰고 할 수 있는지는 잘 모르겠습니다.

 


앞서 말했듯 ViewModel은 아래와 같이 Activity나 Fragment와는 다른 LifeCycle을 가지고 있습니다.(더 긴)

기존의 안드로이드에서는 화면 회전이 발생하는 경우 Activity가 새로 생성되게 되는데 이때 UI데이터들을 보존하기 위해 Bundle에 넣는다거나 귀찮은 짓을 해줘야 합니다. 

 

그러나 아래와 같이 ViewModel의 Scope는 Activity와 관련없이 쭉 유지되므로 데이터가 유실될 걱정을 할 필요가 없습니다. 대신 이러한 이유로 인해 ViewModel이 View에 대한 reference를 가지고 있으면 아주 위험합니다(메모리 leak). 

 

따라서 우리는 LiveData를 이용한 Observer Pattern을 이용하여 이를 처리합니다. 또한 우리는 Activity에서 lifecycleowner를 등록해주면 Activity가 Destroy 되었을때  자동으로 observe가 제거되므로 메모리 leak에서 안전할 수 있습니다.

 


📝Data Reposiotry 적용

 

 

많은 앱들이 다양한 Data Source를 가지고 있습니다. 실제로 제가 만든 롤알리미도 2가지로 나누어져 있습니다.

 

1. SharedPreferences - local

2. Remote: API 호출 

 

data layer를 따로 두는 것을 Reposiotry 패턴을 적용한다고 말하는 것 같습니다. 만약 Reposiotry 패턴을 적용하지 않는다면 ViewModel에서 API 호출 및 SharedPreferences에 직접 접근해야 할 것입니다. 이렇게 되면 ViewModel이 알아야 할 것들이 점점 많아지게 됩니다. 따라서 Domain layer를 추가하여 single point of entry를 두는 것이 좋습니다.

 

 


📝ViewModel의 Leaking 가능성

 

만약 유저가 앱을 나간다고 가정해보겠습니다.(뒤로가기 버튼을 눌러서) 그렇다면 View는 Destroy 될것이며 더이상 ViewModel을 Observe하지 않게 됩니다. 그런데 만약 이때 repository가 singleton 이거나 Application 단의 scope을 가지고 있다면 repository는 프로세스가 kill 될때까지 파괴되지 않을 것입니다. 이때 만약 repository가 ViewModel에 대한 reference를 가지고 있다면 이때 Viewmodel이 누수 될 가능성이 있습니다. 

 

이러한 문제를 해결하기 위해 여러가지 방법들이 있을 수 있습니다.

 

1. ViewModel의 onCleared를 이용 합니다. -> repository에게 ViewModel에 대한 callback을 drop하라고 알려줌

 

2. ViewModel - Repository 사이에 LiveData를 활용합니다. (View와 ViewModel이 이용하는 것과 유사한 방식으로)

 

따라서 위와 같은 구조로 나타날 수 있습니다. 

 

그런데 ViewModel에서는 lifecycleowner를 넣어줄 수 없습니다.(아마) 따라서 Repository의 LiveData가 ViewModel이 파괴되었는지 알 방법이 필요합니다. 이때 Transformations를 사용하면 된다고 합니다. (실제로 이건 사용해본적이 없지만 LiveData가 다른 LiveData를 MediatorLiveData를 이용하여 observe할 때 이용하는 거라고 알고 있습니다.)

 

 


이번글은 여기서 마치려고 합니다. 처음으로 아키텍처 패턴을 적용하기 위해 굉장히 많은 자료들을 참고 하였고 실제로 사람들마다 구현방식에 어느정도 차이가 있었습니다.

 

아키텍처 패턴 적용을 하는데 있어 어려웠던 점은 이코드는 여기 있으면 안될 것 같은데 옮기려니 이런 문제가 있네.. 옮기려면 어떻게 해야할까?, 이코드는 어디로 가야하지? 와 같은 고민을 많이 했던 것 같습니다. 분명 쉽게 적용 할 수 있진 않지만 조금이라도 적용하려고 노력하고 시도 해본 결과 코드가 우아해진다, 클린해진다라는 느낌을 확실히 받았던 것 같습니다. 아키텍처 패턴에 정답은 없다고 생각합니다. 특정 아키텍처 패턴이 가장 좋다고도 할 수 없지만 패턴 자체를 적용시켜 프로그램을 만드는 것은 중요한 일이라 생각합니다.

 

MVVM 패턴은 특히 이를 쉽게 구현하기 위한 여러가지 도구들이 많이 존재하고 있습니다.

AAC의 ViewModel, LiveData, DataBinding +  DI(Dagger2 or Koin) + Repository 패턴들을 적절히 이용한다면 MVVM에 어느정도 가까워 질 수 있지 않을까! 하는 생각을 합니다.

반응형