Search code examples
androidkotlindependency-injectionsingletonkoin

Koin singleton inject constructor with private parameter


Hello I am just learning Koin, how would this Dagger2 class be provided in Koin 2.0?

@Singleton
open class AppExecutors(private val diskIO: Executor, private val networkIO: Executor, private val mainThread: Executor) {

    @Inject
    constructor() : this(
            Executors.newSingleThreadExecutor(),
            Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1),
            MainThreadExecutor())

    fun diskIO(): Executor {
        return diskIO
    }

    fun networkIO(): Executor {
        return networkIO
    }

    fun mainThread(): Executor {
        return mainThread
    }

    private class MainThreadExecutor : Executor {
        private val mainThreadHandler = Handler(Looper.getMainLooper())
        override fun execute(command: Runnable) {
            mainThreadHandler.post(command)
        }
    }
}

I tried this:

single<AppExecutors> { AppExecutors(
    Executors.newSingleThreadExecutor(),
    Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1),
    AppExecutors.MainThreadExecutor())
}

But AppExecutors.MainThreadExecutor() is private. Is the only solution to make it public?


Solution

  • Well, it's a bit strange idea to inject something that is a private implementation detail from outside using DI.

    Also the solution in Dagger2 is a trick which actually works around the dependency injection.

    So you need to do the decision: do I want it to be a private implemietation detail? If yes I would suggest to use a default parameter value and use injection only when you need to override this implementation e.g. for testing.

    open class AppExecutors(
        private val diskIO: Executor, 
        private val networkIO: Executor, 
        private val mainThread: Executor = AppExecutors.MainThreadExecutor()) {
    

    And:

    single<AppExecutors> { AppExecutors(
        Executors.newSingleThreadExecutor(),
        Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1)))
    }
    

    (Keep in mind that using default paramter values in Kotlin is in the end the same as using multiple constructors in the original example.)

    Otherwise you should make it public and extract it from the class.