Android Compose, Hilt Project에 Airbnb Mavericks 2.0 적용

릐라·2025년 3월 5일

Airbnb Mavericks에서는 Compose와 Dagger/Hilt를 모두 지원한다.
이를 사용하기 위해서는 기존 mavericks와 더불어 mavericks-compose, mavericks-hilt를 추가해주어야 한다.

// build.gradle

// mavericks
implementation("com.airbnb.android:mavericks:3.0.9")
implementation("com.airbnb.android:mavericks-compose:3.0.9")
implementation("com.airbnb.android:mavericks-hilt:3.0.9")

// compose
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3-android")

// di
implementation("com.google.dagger:hilt-android:2.51.1")
implementation("com.google.dagger:hilt-android-compiler:2.51.1")
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")

Compose와 Hilt를 사용한 프로젝트에 Mavericks를 도입한다고 해서 기존 코드에 큰 변화를 줄 필요는 없다.

state

먼저 기존 State에 MavericksState를 implement 하면 MavericksState가 된다.

data class AppState(
    val property1: Int = 0,
    val property2: Int = 0
): MavericksState

ViewModel

다음으로 AppViewModel의 @Inject를 @AssistedInject로 변경한 후 constructor에서 @Assisted Annotation을 추가하고 사용할 State를 명시하면 된다.
이후
AssistedViewModelFactory<ViewModel, State>,
MavericksViewModelFactory<ViewModel, State> 두 코드를 추가해주면 된다.

State를 변경할 때는
setState { copy(property = newValue) } 를 사용하면 State를 업데이트 한다.

만약 initialState를 companion object의 initialState를 override해서 초기값의 리턴을 바꿔줄 수 있다.

아래와 같은 형식으로 ViewModel을 선언한다.

class AppViewModel @AssistedInject constructor(
    @Assisted initialState: AppState
) : MavericksViewModel<AppState>(initialState) {

    @AssistedFactory
    interface Factory : AssistedViewModelFactory<AppViewModel, AppState> {
        override fun create(state: AppState): AppViewModel
    }
    
    companion object :
        MavericksViewModelFactory<AppViewModel, AppState> by hiltMavericksViewModelFactory()
}

이 후 AppViewModelModule을 생성하여 viewModel에서 선언한 viewModelFactory의 의존성 주입 코드를 작성해주어야 한다.
아래와 같은 형식으로 작성을 하면 ViewModel과 관련된 변경은 끝이다.

@Module
@InstallIn(MavericksViewModelComponent::class)
interface AppViewModelModule {
    @Binds
    @IntoMap
    @ViewModelKey(AppViewModel::class)
    fun appViewModelFactory(factory: AppViewModel.Factory): AssistedViewModelFactory<*, *>
}

View

@Composable
fun AppView() {
    val viewModel: AppViewModel = mavericksViewModel()
    val property2 by viewModel.collectAsState(AppState::property2)

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Property1View()
        Spacer(modifier = Modifier.size(16.dp))
        Property2View(
            property2 = property2,
            decreaseProperty2 = { viewModel.sendIntent(AppIntent.DecreaseProperty2) },
            increaseProperty2 = { viewModel.sendIntent(AppIntent.IncreaseProperty2) })
    }
}

Compose에서 기존에는 viewModel을 사용할 때
val viewModel: AppViewModel = hiltViewModel()을 사용했다면
val viewModel: AppViewModel = mavericksViewModel()로 바꿔주면 viewModel을 사용할 수 있다.

위에서 viewModel에 주입한 State를 View에서 사용할 때는
val property by viewModel.collectAsState(AppState::property) 와 같이 사용하면 property의 변화를 감지해서 UI에서 즉각적으로 렌더링을 수행할 수 있다.

0개의 댓글