Android-CleanArchitecture-Kotlin icon indicating copy to clipboard operation
Android-CleanArchitecture-Kotlin copied to clipboard

Replace Dagger 2 with Koin

Open stanbar opened this issue 6 years ago • 5 comments

Hello. Here is a fork where I did migration from Dagger2 to Koin. Take a look how much boilerplate code I was able to get rid of. Don't you think that it's much simpler, easier, faster and cleaner way ?

  • No regenerate & recompile required
  • No annotations required
  • self described Kotlin DSL

stanbar avatar Jun 25 '18 12:06 stanbar

DI was out of scope of this, although that does not mean we can discuss about different approaches we can use. Also the fact we are using Dagger is an implementation details. :)

android10 avatar Jun 25 '18 12:06 android10

Hi @stasbar , Just curious on your experience in replacing Dagger2. Was it smooth ? or You did a lot of refactoring / changes when shifting the library used?

crjacinro avatar Jun 26 '18 15:06 crjacinro

@android10 You are right, it's implementation detail. But, I was curious if you chose Dagger2 purposely in this project, if it's the clean way of DI.

@crjacinro It was very smooth. I didn't add any new class, interfaces or anything like that. Here is great article about migration from Dagger to KOIN. Basically removed whole di package and created one file with modules, which is much simpler since you have everything in one place. (Main reason I don't like Dagger, is it classes complexity and high entry point). Additionally I removed all @Inject annotations, and changed way of injection from

@Inject lateinit var movieDetailsAnimator: MovieDetailsAnimator
private lateinit var movieDetailsViewModel: MovieDetailsViewModel
override fun onCreate(savedInstanceState: Bundle?) {
    ...
    appComponent.inject(this)
    movieDetailsViewModel = viewModel(viewModelFactory)
    ...
}

to

private val movieDetailsAnimator: MovieDetailsAnimator by inject()
private val movieDetailsViewModel: MovieDetailsViewModel  by viewModel()

vals always on 👍

I'm quite experienced in KOIN and it's brother project Kodein, so it took me only about 20min.

stanbar avatar Jun 27 '18 09:06 stanbar

Okay, but by viewModel() creates the ViewModel with new instance factory, no? That's typically not what you want and want to use your own ViewModelProvider.Factory

Zhuinden avatar Jun 27 '18 10:06 Zhuinden

@Zhuinden from the documentation

The by viewModel() function lazily calls the ViewModel class instance and bind it to internal ViewModels factory.

And here is also implementation

fun <T : ViewModel> LifecycleOwner.getViewModelByClass(
    fromActivity: Boolean = false,
    clazz: KClass<T>,
    key: String? = null,
    name: String? = null,
    parameters: Parameters = emptyParameters()
): T {
    KoinFactory.apply {
        this.parameters = parameters
        this.name = name
    }
    val viewModelProvider = when {
        this is FragmentActivity -> {
            Koin.logger.log("[ViewModel] get for FragmentActivity @ $this")
            ViewModelProvider(ViewModelStores.of(this), KoinFactory)
        }
        this is Fragment -> {
            if (fromActivity) {
                Koin.logger.log("[ViewModel] get for FragmentActivity @ ${this.activity}")
                ViewModelProvider(ViewModelStores.of(this.activity), KoinFactory)
            } else {
                Koin.logger.log("[ViewModel] get for Fragment @ $this")
                ViewModelProvider(ViewModelStores.of(this), KoinFactory)
            }
        }
        else -> error("Can't get ViewModel on $this - Is not a FragmentActivity nor a Fragment")
    }
    return if (key != null) viewModelProvider.get(
        key,
        clazz.java
    ) else viewModelProvider.get(clazz.java)
}

where KoinFactory is singleton factory

object KoinFactory : ViewModelProvider.Factory

stanbar avatar Jun 27 '18 11:06 stanbar