TIL

[TIL] Kotlin SharedViewModel 개념

정상호소인 2023. 11. 21. 21:00

Topic =  하나의 Activity에서 여러 Fragment를 사용하는 경우 ViewModel을 어떻게 작성하고 관리하면 좋을까

 

 


 

 

✔️ 간단하게 SharedViewModel을 사용하고 생긴 문제들을 먼저 적어보고 SharedViewModel 에 대해서 정리

 

 

 

Why - SharedViewModel은 만능이 아니다.

 

   글 작성일 기준 마지막으로 진행했었던 프로젝트에서는 Single Activity Architecture를 적용하여 프로젝트를 진행하였고 비즈니스 로직과 Fragment 간의 데이터 이동을 관리하는 SharedViewModel 하나로 여러 Fragment에서 사용할 수 있도록 해주었는데 아래와 같은 불편함이 있었다.

  • 코드 가독성 저하
    • 여러 Fragment에서 공유하지 않는 로직인데도 하나의 ViewModel에 모여 있어 코드 전체적인 가독성이 떨어졌다.
  • 유지 보수성 저하
    • 게시글 이미지를 불러오는 로직 같은 경우 여러 Fragment에서 사용하는 로직인데, 특정 Fragment에는 다르게 작동하도록 하고 싶으면 별도로 로직을 분리해주어야 했다.
    • 프로젝트 내에서는 게시글 이미지를 불러오는 로직에서 List형식의 여러 이미지를 가져오는 로직을 단일 Uri 이미지로 가져오는 로직으로 분리하지 않아서 단일 이미지를 필요로 하는 상황에서도 List 형태로 데이터를 가져와 ImageList[0] 으로 이미지를 가져와야 하는 불편함이 생겼다.
  • 의존성 및 결합도 증가
    • 위의 유지보수성 저하와 같이 여러 Fragment에서 SharedViewModel의 동일한 비즈니스 로직을 사용하고 있을 때 해당 로직을 변경할 경우 예기치 못한 오류가 생겨 로직을 분리해주어야 했다.

 

 

 

그렇다면 SharedViewModel은 언제 사용하면 좋을까?

 

 

 

   해당 질문의 답을 얻기 위해서 Android Develpoers에서 AAC - ViewModel의 개념에 대해서 다시 한번 확인 해보았는데, ViewModel 개요가 시작되는 첫 소제목의 ViewModel의 이점에서 데이터 지속성을 위한 편리한 API를 제공한다는 내용을 확인할 수 있다.

 

  • 비즈니스 로직을 관리하는 경우에는 SharedViewModel을 사용하는 방법이 좋지 않다는 것을 알게 되었고, 그렇다면 ViewModel의 비즈니스 로직을 관리하는 것 외에 다른 이점인 Data 관리에 SharedViewModel이 사용되는 방법을 찾아 보았다.

 

 

SharedViewModel 

 

간단한 SharedViewModel 단면도

 

[ 개요 ] 

   앱 개발을 하다보면 다양한 요구 사항에 따라 여러 화면에서 동일한 데이터를 공유해야 하는 경우가 있다. 진행중인 프로젝트가 SAA ( Single Activity Architecture ) , MAA ( Multi Activity Architecture ) 각각에 따라 View의 Lifecycle에 맞게 데이터를 관리할 수 있도록 해주어야 한다.

 

   ViewModel은 수명주기를 고려하여 UI 관련 데이터를 안정적으로 저장하고 관리할 수 있으며 SharedViewModel은 여러 Fragment가 동일한 ViewModel 인스턴스를 공유하여 데이터를 주고받을 수 있도록 하고, 이를 위해 SAA 방식으로 Activity 범위에서 ViewModel이 생성되어 여러 Fragment들이 이를 참조하여 데이터를 공유할 수 있도록 한다. 

 

 

[ 장점 ]

  • 간결함
    • 여러 Fragment에서 동일한 ViewModel 인스턴스를 공유하므로, Fragment 간에 데이터를 쉽게 공유하고 전달할 수 있다.
  •  상태 유지
    • SharedViewModel은 Activity의 생명주기에 종속되므로, Fragment 간의 전환 또는 구성 변경과 같은 상황에서도 데이터의 일관성과 상태를 유지할 수 있다. 이는 사용자 경험을 향상시키고 데이터의 유지보수성을 높인다.

 

 

[ Bundle, ResultListener 를 사용하는 방법보다 SharedViewModel을 통한 데이터 이동이 권장되는 이유 ]

  • 데이터의 실시간 동기화
    • A Fragment에서 데이터를 업데이트하면 다른 Fragment 들도 동일한 데이터를 즉시 참조할 수 있다. 이는 데이터의 일관성과 실시간 동기화를 보장한다.
    • Bundle, ResultListener의 경우 Fragment의 생명주기와 데이터의 동기화를 직접 관리해야 하므로 코드의 복잡성이 증가할 수 있어 SharedViewModel을 통해 번거로운 데이터 전달과 동기화 작업을 피할 수 있다.
  • 확장성과 유연성
    • SharedViewModel은여러 Fragment 간에 데이터를 공유하므로, 프로젝트의 규모가 커지거나 변경이 발생해도 유연하게 코드를 작성할 수 있다. 새로운 Fragment가 추가되어도 기존의 SharedViewModel에 접근하여 데이터를 사용할 수 있어 효율적인 처리가 가능하다.
  • 단방향 통신 vs 양방향 통신
    • Bundle, ResultListener 를 통한 데이터 이동 시 양방향 통신이 이루어지고, SharedViewModel을 통한 데이터 이동 시 ViewModle을 통해서만 데이터가 업데이트되고 공유되므로 흐름이 단방향으로 유지된다. 이는 데이터의 일관성과 예측 가능성을 높여준다.
  • 테스트 용이성
    • Bundle, ResultListener를 사용하여 데이터를 이동시키는 경우 Fragment 간의 상호작용을 테스트하기 위해 추가적인 객체나 관리 작업이 필요하지만 SharedViewModel을 사용하는 경우 Fragment와 VIewModel을 독립적으로 테스트할 수 있어 ViewModel의 동작을 테스트하는 데 집중할 수 있다. 

 

[ 주의할 점 ]


여러 Fragment에서 공유되는 데이터 관리에 SharedViewModel을 사용할 때 ViewModel과 View 사이에 의존성과 결합도가 증가할 수 있고. 이를 위해 Fragment 간에 공유되는 데이터에서 필요한 데이터는 UseCase Repository와 같이 인터페이스를 Hilt 를 통해 의존성 주입으로 의존성과 결합도를 낮출 수 있다.

이때 DI 모듈 단일 인스턴스를 여러 ViewModel에서 공유하는 경우 @ActivityRetainedScoped 또는 @Singleton 을 사용하여 범위를 지정해주어야 한다. 


[ 의존성 주입 X → View를 거쳐 데이터 전달 ]
이미지 출처 : https://medium.com/@wodbs135/view-lifecycle%EC%97%90-%EB%94%B0%EB%9D%BC-viewmodel-%EA%B0%84-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B3%B5%EC%9C%A0%ED%95%98%EA%B8%B0-c6d9dbf2682b




[ 의존성 주입 O → View를 통하지 않고 ViewModel 간 데이터 공유 ]

이미지 출처 : https://medium.com/@wodbs135/view-lifecycle%EC%97%90-%EB%94%B0%EB%9D%BC-viewmodel-%EA%B0%84-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B3%B5%EC%9C%A0%ED%95%98%EA%B8%B0-c6d9dbf2682b




 

 

 

 

 

 

 

 

 


 

[ A. 오늘 복습한 내용 / B. 다음에 학습할 내용 ]

A. ViewModel과 SharedViewModel 각각 어느 상황에서 사용하면 좋을지 학습

 

B. Hilt를 통한 의존성 주입

 

B. Activity, Fragment, ViewModel 등 앱 전반적인 컴포넌트 생명주기 자세하게 복습, 학습하기

 

 


 

[오류,에러 등등]

1. SharedViewModel에 대해 추가적으로 학습하면서 지난 프로젝트에 부족했던 부분, 구조적인 오류가 발생했던 부분 알게되었다

→ SharedViewModel의 데이터 이동 로직에 매개변수 등을 사용해서 메서드를 분리하지 않고 사용했던 문제, 하나의 ViewModel에 비즈니스 로직과 데이터 이동 로직이 모두 포함되었던 문제

 

해결방법

→ 각 Fragment 별로 데이터를 관리하는 ViewModel과 비즈니스 로직을 관리하는 ViewModel 2개로 분리하는 코드로 먼저 작성 후 정상적인 구조가 될 경우 Hilt를 통해 의존성 관리 리팩토링 예정.

 

 


 

[느낀 점]

1. 꾸준하게 학습하면서 TIL을 작성할 수 있도록 노력해야겠다. 

 


[Reference]

 

// ViewModel

 

ViewModel 개요  |  Android 개발자  |  Android Developers

ViewModel을 사용하면 수명 주기를 인식하는 방식으로 UI 데이터를 관리할 수 있습니다.

developer.android.com

 

앱 아키텍처 가이드  |  Android 개발자  |  Android Developers

앱 아키텍처 가이드 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 가이드에는 고품질의 강력한 앱을 빌드하기 위한 권장사항 및 권장 아키텍처가 포함

developer.android.com

 

// SharedViewModel의 의존성 관리

 

 

View Lifecycle에 따라 ViewModel 간 데이터 공유하기

Sharing data between ViewModels

medium.com