Android Hilt 적용해보기 🗡️

푸른하늘·2022년 6월 21일
0
post-thumbnail

🍎 의존성 주입(DI)이 뭐야?

의존성 주입은 Android Studio 개발 환경에서 가장 주목받고 있는 디자인 패턴중 하나인데 각종 컴포넌트간 의존성이 강한 Android FrameWork의 의존성을 낮춰다는 것은 엄청난 효과와 의미를 부여하기 때문에 자주 사용됩니다.

🍏 DI로 얻는 장점은?

  • 코드 재사용 가능
  • 리팩토링 편의성
  • 테스트 편의성 (Stub 또는 Mock 객체 사용 단위테스트 easy)
  • 클래스 간 결합도를 느슨하게함
  • 인터페이스 기반으로 설계되며 , 코드를 유연하게 한다

🍏예시

class Car{
	private val engine = Engine()
    
    fun start(){
    	engine.start()
    }
}

fun main(args: Array){
	val car = Car()
    car.start()
}

다음 코드를 보면 Car 클래스안에 Engine을 구성하고 있습니다. 그러므로
Car와 Engine은 긴밀하게 연결되어 있고 이로 인해 테스트 및 테스트 더블을 사용하여 수정을 할 수 없게 된다.

🍏개선된 예시

class Car(private val engine: Engine){
	fun start(){
     	engine.start()
    }
}
fun main(args: Array){
    val engine = Engine()
    val car = Car(engine)
    car.start()

}

다음은 외부에서 Engin객체를 생성하고 이를 사용하여 Car생성자 매게변수로 Engine() 겍체를 전달합니다 구성합니다. 이 방법이 DI 접근이랑 같은데 이로 생기는 장점

  • Car의 재사용 가능 Engine의 다양한 구현을 Car에 전달할 수 있습니다.
    ex) Engine() or EletroicEngine() or GasEngine()
  • Car의 테스트 편의성 및 테스트 더블을 전달하여 다양한 시나리오를 테스트 할 수 있습니다.

🍏안드로이드에서 의존성 주입 어려운 이유?

안드로이드에서 사용하는 Activty ,Fragment ,Service같은 경우는 Android프레임워크가 직접 인스턴스화 하기 때문에 사용자가 직접적으로 전달할 방법이 없습니다. 그래서 안드로이드에서 Dagger2(단검) 라이브러리를 개발하였습니다.

🍏Dagger2 의 특징

  • 컴파일 타임에 Anotation 을 사용하여 의존성 관련 코드 생성
  • 생성된 코드는 명확하고 디버깅이 가능함
  • 리플렉션 사용 X, 런타임 바이트 코드 생성 X
  • 계층별로 잘 정리된 생명주기 속에서 객체들이 공유할 수 있는 방법 제공

리플렉션 : 클래스, 인터페이스, 메소드들을 찾을 수 있고, 객체를 생성하거나 변수를 변경할 수 있고 메소드를 호출할 수도 있습니다. Reflection은 자바에서 기본적으로 제공하는 API

🍏Dagger2 의 단점

  • 배우기 어렵고 , 설정하기가 힘들다.
  • 간단한 프로그램을 만들 때는 번거롭다
  • 같은 결과에 대한 다양한 방법이 존재한다.

이로써 날카로운 Dagger2의 단점을 보안하기 위해 Hilt(자루)가 생겨 났다.
Dagger-Hilt == 단검 + 자루

🍎Hilt의 목표 및 사용법

  • DI를 사용하는 표준적인 방법을 제공한다
  • Dagger 의 사용의 단순화
  • 쉬운 방법으로 다양한 빌드 타입에 대해 다른 바인딩 제공
  • AndroidX 라이브러리의 호환
  • 보일러플레이트 코드 감소

🍏 종속성 추가

build.gradle(Project: 프로젝트명)

buildscript {
    dependencies {
        classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
    }

}

build.gradle(Modlue: 프로젝트명)

apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'


dependencies {
    implementation "com.google.dagger:hilt-android:2.28-alpha"
    kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
}

🍏 Hilt Quick Setup

  1. 어플리케이션클래스에 : Application() 추가
@HlitAndroidApp
class AppName : Application()
  1. mainfest에서 android:name => AppName 으로 설정
<application
        android:allowBackup="true"
        android:name=".AppName"  
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MVVMTodoApp">
  1. Repository에 어노테이션 @Modlue @InstallIn(SingletonComponent::class)
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
	// @InstallIn : Hilt가 생성하는 DI 컨테이너에  어떤 모듈을 사용할지 가리킨다.
    @Provides
    @Singleton
    fun provideTodoRepository(db: TodoDatabase): TodoRepository{
        return TodoRepositoryImpl(db.dao)
    }
}

@Singleton 어노테이션을 사용하는 이유는

Repository 인스터스를 생성할 때 같은 주소를 가르키도록 설정하여 중복생성을 막기 위함입니다.

🍏 @AndroidEntryPoint 지원타입

  • Activity @AndroidEntryPoint
  • Fragment @AndroidEntryPoint
  • View
  • ViewModel @HiltViewModel
  • Service
  • BroadcastReceiver

🍏구성요소 계층 구조


해당 파일에 알맞는 컴포넌트를 추가하며 화살표 방향 기준으로 하위 컴포넌트는 상위 컴포넌트에 접근 할 수 있습니다.

🍏 Hilt Component 특징

  • Dagger와 다르게 직접적으로 인스턴스화 할 필요가 없음
  • 표준화된 컴포넌트 세트와 스코프를 제공한다

🍏 Custom Component

  • 표준 Hilt외의 새로운 컴포넌트를 만드는 것은 사용하면 복잡하고 이해하기 어려워지기 때문에 꼭 필요한 경우에만 사용

🍎마치며

Hlit는 클라이언트의 보일러 플레이트코드 및 안드로이드가 가지고있는 생명주기를 관리할수 있었고
추가로 알아야할 Hilt 개념

  • Scope
  • Qualifier
  • Entry Point

왜 쓰는지 더 자세히 알고 싶다면

  • 클린 아키텍쳐 Book 참고
  • 디자인 패턴 참고

머리가 복잡하고 어지럽다면 잘 따라오고 있는것이다.

📢 깃허브 자료
TodoApp => Hilt + Compose + Room + MVVM

참조문서

profile
Developer-Android-CK

0개의 댓글