[Noeul] DI로 koin을 선택한 이유

love&peace·2024년 9월 27일

neoul

목록 보기
1/2
post-thumbnail

What is Koin?!

Koin is a pragmatic and lightweight dependency injection framework for Kotlin developers.
(Koin은 Kotlin 개발자를 위한 실용적이고 가벼운 종속성 주입(DI) 프레임워크입니다.)
Koin is a DSL, a light container and a pragmatic API
(Koin은 DSL이자 가벼운 컨테이너이자 실용적인 API입니다.) - koin 문서

DSL은 특정 도메인에 국한해 사용하는 언어이다.
따라서, koin은 kotlin에 최적화된 DI 라이브러리입니다

의존성 주입(DI)?

객체 간의 의존성을 외부에서 주입해주는 설계 패턴으로 이를 통해 객체가 다른 객체에 직접 의존하지 않고, 필요한 의존성을 외부에서 주입받아 결합도를 낮춥니다. DI는 코드의 유연성, 재사용성, 테스트 용이성을 높이는 데 기여한다.

Noeul 프로젝트에서 DI가 필요한 이유는?

MVVM 패턴을 더욱 잘 이용 + 생명주기와 상관없이 데이터 관리

  • MVVM 패턴에서 ViewModel에 필요한 비즈니스 로직을 DI를 통해 주입받음으로써 View와 Model 간의 결합도를 줄이기 위해서
  • Singleton 객체를 정의하여 생명주기와 상관없이 상태관리하기 위해서

koin을 사용한 이유

장점

  • 러닝커브가 낮아 쉽고 빠르게 DI를 적용할 수 있습니다.
  • Kotlin 개발 환경에 도입하기 쉽습니다.
  • 별도의 어노테이션을 사용하지 않기 때문에 컴파일 시간이 단축됩니다.
  • ViewModel 주입을 쉽게 할 수 있는 별도의 라이브러리를 제공합니다.

단점

  • 런타임 시 의존성 주입 -> 런타임 중 에러가 발생할 가능성

선택한 이유는 쉬워서!! + 팀원들은 DI 경험이 없다고 하기도 해서..

그당시 막 안드로이드를 공부하던 시기여서.. 지금은 단점이 치명적이여서 hilt를 더 선호 합니다..ㅎㅎ

neoul의 module

val appModule = module {

    single { Dispatchers.IO }
    single { Dispatchers.Main }

    //network
    single { provideNeoulRetrofit(get(), get()) }
    single { providerGsonConvertFactory() }
    single { buildOkHttpClint() }

    //Api
    single { provideStoryApiService(get()) }
    single { provideBrandApiService(get()) }
    single { provideProductApiService(get()) }

    //loginApi
    single { provideLoginApiService(get()) }

    single<LoginRepository> { DefaultLoginRepository(get(), get()) }


    //SignUpApi
    single { provideSignUpApiService(get()) }

    single<SignupRepository> { DefaultSignupRepository(get(), get()) }

    //MyPageApi
    single { provideMyPageApiService(get()) }
    single<MyPageRepository> { DefaultMyPageRepository(get(), get()) }


    //Repository
    single<StoryRepository> { DefaultStoryRepository(get(), get()) }
    single<BrandRepository> { DefaultBrandRepository(get(), get()) }
    single<ProductRepository> { DefaultProductRepository(get(), get()) }

    //util
    single { ApplicationPreferenceManager(androidApplication()) }
    single { MainMenuBus() }
    single { CategoryMenuBus() }

    //VM
    viewModel { HomeViewModel(get(), get(), get()) }
    viewModel { EventViewModel() }
    viewModel { (categoryId: Int, categoryId2: Int) ->
        CategoryViewModel(get(), categoryId,categoryId2)
    }
    viewModel { BrandViewModel(get()) }
    viewModel { (brand: BrandItem) -> BrandDetailViewModel(brand, get()) }
    viewModel { StoryViewModel(get()) }
    viewModel { (story: Story) -> StoryDetailViewModel(story, get()) }
    viewModel { MyPageViewModel(get()) }
    viewModel { (product: Product) -> ProductViewModel(product, get()) }
    viewModel { SearchViewModel(get() ,get()) }
    viewModel { LikeListViewModel(get(), get()) }

}

Single : 싱글톤 객체로 생성합니다.
Factory : 요청 시 마다 매번 새로운 객체를 생성한다.
ViewModel : viewModel에 대한 객체를 생성합니다.
get : 컴포넌트 내에서 알맞은 의존성을 주입합니다.
named("~~~") : get() 으로 받을때 동일한 타입의 객체를 구분하기 위해

의존성 주입하기

BrandDetailActivity.kt

class BrandDetailActivity : BaseActivity<BrandDetailViewModel, ActivityBrandDetailBinding>() {

    override val viewModel by viewModel<BrandDetailViewModel> {
        parametersOf(
            intent.getParcelableExtra(BRAND_KEY)
        )
    }

    private val mainMenuBus by inject<MainMenuBus>()
    ///****///

BrandDetailViewModel.kt

class BrandDetailViewModel(
    private val brand: BrandItem,
    private val brandRepository: BrandRepository
) : BaseViewModel() {

    private var jwt = ""

    val brandDetailStateLiveData = MutableLiveData<BrandDetailState>(BrandDetailState.Uninitialized)
    val brandLikedLiveData = MutableLiveData<Boolean>(null)
    val productListLiveData = MutableLiveData<List<Product>>()

    override fun fetchData() = viewModelScope.launch {
  • viewModel 주입 (+ repository (비지니스 로직))
  • 생명주기와 상관없이 상태관리 : main activity의 바텀 내비 값 주입

** brend detail -> main (brend -> my page) ,
brand detail 엑티비티의 finish 하면서 main 엑티비티의 bottomNavi(fragment) 전환하기 위해 singleton 객체 사용

[Neoul 깃헙]
https://github.com/UMC-neoul/NEOUL_FRONT/blob/develop/Neoul/app/src/main/java/com/umc/neoul/di/appModule.kt

0개의 댓글