2

I am trying to implement a clean code architecture similar to what's described here. To enforce it, each layer is a separate module in Android Studio with the dependency chain thus:

model(pure-kotlin) -> interactor(pure-kotlin) -> viewmodel(android) -> view(android)

So to be clear, the view only knows about the viewmodel and the viewmodel only knows about the interactor. The view (normally the app module) is where the MainActivity lives.

I am currently working on the interactor in isolation and I am trying to use Dagger 2 for injection there. I have written the following code all in the interactor module:

... (Build.gradle)
implementation 'com.google.dagger:dagger:2.20'
kapt 'com.google.dagger:dagger-compiler:2.20'
...

abstract class ApiServiceInteractor() {
    @Inject lateinit var apiService: ApiService
    @Inject lateinit var schedulers: InteractorSchedulers
}

class Posts @Inject constructor() : ApiServiceInteractor() {
    fun fetch(): Single<List<PostSummary>> =
        apiService.getPosts()
            .subscribeOn(schedulers.io())
            .toObservable()
            .flatMapIterable { postList -> postList }
            .map { post -> PostSummary(post.id, post.title) }
            .toList()
}

@Module
open class InteractorModule {
    @Singleton @Provides 
    open fun provideApiService(): ApiService = ApiService.create()

    @Provides 
    open fun provideSchedulers(): InteractorSchedulers = InteractorSchedulers()
}

@Component
interface Component {
    fun inject(posts: Posts)
}

val dagger = DaggerComponent.create() // <--- not generated!!!

The code does not compile. The compiler complains that the injected apiService and schedulers in ApiServiceInteractor need a corresponding @Provides, furthermore the DaggerComponent implementation is not auto-generated. Now, I realise that the Component interface doesn't make sense here, but you need one to auto-generate DaggerComponent and this is just prototyping at this stage.

If I move the Component interface and the DaggerComponent.create() into the view (and have the inject signature use MainActivity instead of Posts) then everything compiles fine and DaggerComponent is created.

My worry is that when everything is finally written, Dagger will not be able to resolve the @Provides for apiService and schedulers because there is a degree of separation between the view and the interactor (where the @Provides are). The only examples I have seen that are anything similar to this have the @Provides in the view (app) module. If I do that, however, I will break the clean code architecture dependency rule because the view will then have a dependency on the interactor.

So will it work the way it is? Will those values get injected?

UPDATE

I removed the '@Component' and 'DaggerComponent' declarations from view, put them back in interactor and added '@Component(modules = [InteractorModule::class])'. The compiler no longer complains about missing provides (thanks Ivan), but the IDE still reports that DaggerComponent does not exist. Calling DaggerComponent.create().inject(this) in Posts init does not compile because DaggerComponent has not been generated.

So it appears that DaggerComponent can only be generated in the view module which means that the @Component declaration also has to be in the view module, along with the modules = [InteractorModule::class] annotation parameter. And once you do that, you have a dependency between view and interactor on InteractorModule, breaking the clean code architecture dependency rule.

So the main question still remains, how to get Dagger 2 to work in a pure-Kotlin module removed from the Android layer?

Myles Bennett
  • 533
  • 4
  • 12
  • 1
    I'm not Dagger expert but, shouldn't your component have its Modules declared? e.g. @Component(modules = [ContextModule::class]) – Ivan Wooll Feb 19 '19 at 09:29
  • Please always include the actual error message (_compiler complains that the injected apiService and schedulers in ApiServiceInteractor need a corresponding @Provides_). It sounds like you have an error with your dependencies, please read here about [How do I fix Dagger 2 error … cannot be provided](https://stackoverflow.com/q/44912080/1837367) – David Medenjak Feb 19 '19 at 09:37

0 Answers0