Я пытаюсь реализовать архитектуру чистого кода, аналогичную описанной здесь .Для обеспечения этого каждый слой в Android Studio представляет собой отдельный модуль с цепочкой зависимостей, таким образом:
модель (pure-kotlin) -> интерактор (pure-kotlin) -> viewmodel (android) ->view (android)
Итак, чтобы быть ясным, view
знает только о viewmodel
, а viewmodel
знает только о interactor
.Представление (обычно модуль app
) - это то место, где живет MainActivity
.
В настоящее время я работаю над interactor
изолированно и пытаюсь использовать Dagger 2 для инъекции.Я написал следующий код в модуле interactor
:
... (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!!!
Код не компилируется.Компилятор жалуется, что для вставленных apiService
и schedulers
в ApiServiceInteractor
требуется соответствующий @Provides
, кроме того, реализация DaggerComponent
не генерируется автоматически.Теперь я понимаю, что интерфейс Component
здесь не имеет смысла, но он вам нужен для автоматической генерации DaggerComponent
, и на данном этапе это просто создание прототипа.
Если я переместу Component
Интерфейс и DaggerComponent.create()
в представлении (и используют подпись инъекции MainActivity
вместо Posts), тогда все компилируется и создается DaggerComponent
.
Меня беспокоит то, что, когда все наконец написано,Кинжал не сможет определить @Provides
для apiService
и schedulers
, поскольку существует некоторая степень разделения между view
и interactor
(где @Provides
).Единственные примеры, которые я видел, которые похожи на это, имеют @Provides
в модуле view
(app
).Однако, если я сделаю это, я нарушу правило зависимостей архитектуры чистого кода, потому что view
будет зависеть от interactor
.
Так будет ли оно работать так, как есть?Будут ли введены эти значения?
ОБНОВЛЕНИЕ
Я удалил объявления '@Component' и 'DaggerComponent' из view
, поместил их обратно в interactor
идобавлено «@Component (modules = [InteractorModule :: class])».Компилятор больше не жалуется на отсутствие пропусков (спасибо Ивану), но IDE по-прежнему сообщает, что DaggerComponent не существует.Вызов DaggerComponent.create().inject(this)
в сообщениях init не компилируется, поскольку DaggerComponent не был сгенерирован.
Таким образом, создается впечатление, что DaggerComponent
может быть сгенерировано только в модуле view
, что означает, что объявление @Component
также имеетнаходиться в модуле view
вместе с параметром аннотации modules = [InteractorModule::class]
.И как только вы это сделаете, у вас будет зависимость между view
и interactor
от InteractorModule
, нарушающая правило зависимостей архитектуры чистого кода.
Таким образом, остается главный вопрос, как заставить Dagger 2работать в чистом модуле Kotlin, удаленном из слоя Android?