[Android] Fragment 간 데이터 공유는 어떻게 할 수 있을까? (with. 스타카토)

hxeyexn·2025년 2월 20일
post-thumbnail

오늘은 Fragment 간 데이터를 공유하는 방법에 대해 알아보려고 한다. 다음은 글의 목차이다.

목차

  • Intro
  • SharedViewModel에 대하여
  • AAC ViewModel과 Fragment KTX
  • activityViewModels()이란?
  • activityViewModels()을 활용해 SharedViewModel 만들기
  • 주의할 점
  • Outro

Intro

스타카토의 화면은 하나의 Activity 위에 두 개의 Fragment가 존재하는 구조이다.
스타카토(일상 기록)의 위·경도 값을 StaccatoFragmentMapsFragment가 공유해야 한다.

현재 Fragment 간 데이터 공유를 위해 팀원이 만들어 둔 SharedViewModel을 유용하게 사용하고 있다. 처음 도입했던 건 내가 아니었기에, 완벽하게 이해하지 못하고 사용했던 것 같아 이번에 제대로 공부해 보려고 한다.



SharedViewModel에 대하여

StaccatoViewModel은 서버에 조회한 스타카토 정보를 통해 위경도의 정보를 알고 있지만, MapsViewModel은 위경도를 알 수 없다.

즉, StaccatoViewModel의 스타카토 정보가 observe 되면 StaccatoFragment는 MapsFragment에게 누군가를 통해서 "조회된 스타카토 위경도 정보 여기 있으니깐 가져다 써~"라고 알려줘야 한다.

이때 누군가의 역할을 SharedViewModel이 하는 것이다.



AAC ViewModel와 Fragment KTX

필자는 SharedViewModel을 만들기 위해 AAC ViewModel과 Fragment KTX를 사용했다. AAC ViewModel과 Fragment KTX에 대해 간단하게 알아보자.

AAC ViewModel이란?

우선 AAC(Android Architecture Components)란 구글에서 테스트와 유지 보수가 쉬운 안드로이드 앱을 디자인할 수 있도록 돕는 라이브러리이다.

AAC ViewModel은 AAC의 일부로 UI 관련 데이터를 저장하고 관리하는 역할을 한다. 이 데이터는 화면 회전과 같은 구성 변경이 발생해도 유지된다. 즉, ViewModel을 사용하면 사용자에게 지속적으로 일관된 데이터를 보여줄 수 있다.

Fragment KTX란?

Fragment KTX 공식 문서
The Fragment KTX module provides a number of extensions to simplify the fragment API.

Fragment KTX 모듈은 Fragment의 API를 간소화하기 위한 다양한 확장 기능을 제공해 준다.

SharedViewModel을 만들기 위해 Fragment KTX가 제공하는 API 중 activityViewModels()을 사용할 것이다.



activityViewModels() 이란?

activityViewModels() 공식 문서

Returns a property delegate to access parent activity's ViewModel, if factoryProducer is specified then ViewModelProvider. Factory returned by it will be used to create ViewModel first time.

activityViewModels()은 부모 Activity의 ViewModel에 접근할 수 있는 속성 위임자(Delegated Properties)를 반환해 준다. activityViewModels()의 내부 구현을 살펴보면 Fragment의 ViewModelStoreOwner를 사용하지 않고, requireActivity()를 활용해 Activity의 ViewModelStoreOwner를 사용하고 있는 것을 확인할 수 있다.

@MainThread
public inline fun <reified VM : ViewModel> Fragment.activityViewModels(
    noinline extrasProducer: (() -> CreationExtras)? = null,
    noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> = createViewModelLazy(
    VM::class, { requireActivity().viewModelStore },
    { extrasProducer?.invoke() ?: requireActivity().defaultViewModelCreationExtras },
    factoryProducer ?: { requireActivity().defaultViewModelProviderFactory }
)

즉, Fragment는 자신이 속해있는 Activity의 ViewModel에 접근할 수 있는 것이다!



activityViewModels()을 활용해 SharedViewModel 만들기

먼저 SharedViewModel을 만든다. SharedViewModel을 만드는 방식은 일반 ViewModel을 만드는 방식과 동일하다.

class SharedViewModel : ViewModel() {
    ...
}

SharedViewModel을 만든 후에는 데이터를 주고받을 Fragment들에 activityViewModels()를 이용해 지연 초기화해주면 된다. activityViewModels()을 사용하기 위해선 fragment-ktx 의존성을 추가해 줘야 한다.

build.gradle.kts(:app)

dependencies {
    implementation("androidx.fragment:fragment-ktx:버전")
}
class StaccatoFragment : Fragment() {
     private val sharedViewModel: SharedViewModel by activityViewModels()
    ...
}
class MapsFragment : Fragment() {
     private val sharedViewModel: SharedViewModel by activityViewModels()
    ...
}

SharedViewModel을 사용하고자 하는 Activity에서는 SharedViewModel을 초기화하지 않아도 된다. Activity의 ViewModelStoreOwner를 활용하기 때문에 Activity가 관리하는 ViewModel이 생성된다. Fragment에서 SharedViewModel을 초기화하더라도 각각의 Fragment Lifecycle를 따르는 것이 아니라 Activity Lifecycle을 따른다.

실제로 MainActivity, MapsFragment, StaccatoFragment의 SharedViewModel의 주소 값을 확인해 보면 모두 동일하다는 것을 알 수 있다.



주의할 점

A Activity 위에 A Fragment와 B Fragment가 SharedViewModel을 이용해 데이터를 공유한다. 이때 B Activity에서 SharedViewModel을 사용해 A Activity와 데이터를 공유할 수 있을까? A Activity와 B Activity 사이에서는 SharedViewModel을 활용해 데이터를 공유할 수 없다.

ComponentActivityViewModelStoreOwner를 상속받아 구현한다. 이때 오버라이딩 된 ViewModelStore는 ViewModel 인스턴스들을 map에 저장해 관리한다.

ViewModelStoreOwner

ComponentActivity가 ViewModelStoreOwner 구현

ViewModelStore

따라서 A Activity와 B Activity는 각각 자신의 생명 주기에 따라 ViewModel을 관리하므로 ViewModel을 공유할 수 없다.

이 점만 잘 이해하면 SharedViewModel을 유용하게 사용할 수 있을 것이다.



Outro

요약하면 다음과 같다.

  • activityViewModels()은 부모 Activity의 ViewModel에 접근할 수 있는 속성 위임자(Delegated Properties)를 반환해 준다.
  • activityViewModels()을 활용해 SharedViewModel을 만들 수 있다.
  • SharedViewModel을 이용해 같은 Activity에 존재하는 Fragment 간 데이터 공유가 가능하다.

기술을 사용하기 전에 제대로 학습하고 활용해야 한다는 것을 다시 한번 깨닫게 해준 포스팅이었다.

profile
Android Developer

1개의 댓글

comment-user-thumbnail
2025년 3월 1일

fragment 간 데이터 전달을 편리하게 할 수 있는 shared viewmodel이군요!
액티비티의 viewmodel scope를 이용하기때문에 그런 것이군요.

답글 달기