깨알 개념/Android

[Android] Dagger2 - Activity에 Dependency 주입

interfacer_han 2024. 6. 25. 06:59

#1 이전 글

 

[Android] Dagger2 - 기초

#1 이전 글 의존성 주입 (Dependency Injection)#1 의존성 주입(Dependency Injection)이란?#1-1 Dependent와 Dependencyfun main() { val car = Car() car.startCar() } class Car { private val engine = Engine() private val airbag = Airbag() private

kenel.tistory.com

위 게시글의 완성된 앱을 일부 수정해서, 'Activity에 의존성을 주입'해본다. 이 말의 의미는 #3-1에 나온다. 

 

#2 @Component 인터페이스 속 getter의 불편함

// package com.example.activitydependencyinjection

import dagger.Component

@Component
interface CarComponent {
    fun getCar(): Car
    
    // fun getMotorcycle(): Motorcycle
    
    // fun getBicycle(): Bicycle
    
    // ...
}

이전 글의 @Component는 위와 같이 getCar()라는 메소드를 제공한다. 하지만, 프로젝트가 점점 커지면 getMotorcycle(), getBicycle() 따위의 getter 함수들이 계속 늘어날 것이다. 이렇게 되면, 필요한 Dependent를 찾기 위해서 getter 함수 목록을 뒤적거리는 비효율적인 상황이 초래된다. 이를 해결하기 위해서 dagger는 Activity에 의존성을 주입하는 기능을 지원한다.

 

#3 Activity에 Dependency를 주입하기

#3-1 @Component 인터페이스 수정

// package com.example.activitydependencyinjection

import dagger.Component

@Component
interface CarComponent {
    fun inject(mainActivity: MainActivity)
}

그것은 바로 위 코드처럼 컴포넌트 클래스를 수정하는 것이다. inject()는 getter 함수들을 하나의 함수로 통합한 함수다. getCar()의 경우 Car를 최종 Dependent로 삼아 의존성 주입을 수행했었다. inject() 또한 MainActivity를 최종 Dependent로 삼아 의존성 주입을 수행한다는 의미다.

 

하지만 inject()는 getCar()와 달리 반환형이 없다. 이는 inject()의 목적과 관련이 있다. inject()는 MainActivity라는 객체를 생성하려는 목적이 아니라, 이미 생성된 MainActivity에 후행적으로 Dependency를 주입하는 메소드다. 따라서 MainActivity의 Dependency들은 MainActivity의 생성과 동시에 초기화되지 않고, lateinit var형으로 선언되어야 한다. #3-2의 코드를 보면 해당 Dependency를 확인할 수 있다.

 

Car의 Dependency들인 Airbag, Battery, Engine에 @Inject 어노테이션을 통해 의존성 주입을 (dagger 라이브러리가 알 수 있게) 명시화했던 것처럼, MainActivity의 Dependency들에게도 의존성 주입 대상임을 명시화해야 한다. 아래 코드를 보자.

 

#3-2 MainActivity.kt 수정

// package com.example.activitydependencyinjection

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import javax.inject.Inject

class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var car: Car

    override fun onCreate(savedState: Bundle?) {
        ...
/*
        ...
*/
        DaggerCarComponent.create().inject()
        car.startCar()
    }
}

이렇게 lateinit var형 프로퍼티를 선언하고 @Inject 어노테이션을 붙인다. @Inject가 생성자에 붙은 경우에는 Constructor Injection(이 링크의 #2-1 참조)이 수행되었던 것처럼, @Inject가 필드(코틀린은 Field가 없으므로, 그 대신 프로퍼티)에 붙은 경우에는 Field Injection(이 링크의 #2-3 참조)이 수행된다.

 

결과적으로, Activity에서 사용할 Dependent들을 @Inject 어노테이션과 함께 선언만 해두면, inject() 메소드에 의해 Dependency가 알아서 주입된다. getter를 일일히 사용할 필요가 없다.

 

#3-3 의존성 그래프

Activity에 의존성 주입을 하는 경우를 의존성 그래프로 나타내면 위와 같다. 본 게시글의 MainActivity가 실제로 Motorcycle이나 Bicycle 프로퍼티를 가지고 있는 것은 아니지만, 이해를 돕기 위해 있는 것처럼 포함시킨 그래프다.

 

#4 작동 확인 (로그 메시지)

Crankshaft is ready
Cylinder is ready
Piston is ready
Engine is ready
Airbag is ready
Battery is ready
Car is ready

 

#5 요약

액티비티도 Dependent가 될 수 있다.

 

#6 완성된 앱

 

android-practice/dagger2/ActivityDependencyInjection at master · Kanmanemone/android-practice

Contribute to Kanmanemone/android-practice development by creating an account on GitHub.

github.com