На прошлом уроке мы создали простое приложение с двумя модулями app и data, и добавили зависимость между ними. Теперь мы в TasksActivity можем создать и использовать Database.

Это все хорошо, но мы хотим Database не руками создавать, а инджектить даггером. Давайте подключать его к проекту.

 

 

Подключение даггера

В обоих модулях в файлах build.gradle добавляем:

build.gradle (:app, :data)

plugins {
  id 'kotlin-kapt'
}

dependencies {
    implementation 'com.google.dagger:dagger:2.42'
    kapt 'com.google.dagger:dagger-compiler:2.42'
}

В последующих создаваемых модулях не забывайте делать те же действия.

 

Чтобы даггер мог предоставлять объекты, нам нужно создать компонент и даггер-модуль (так я буду далее по тексту называть даггеровский @Module, чтобы не путать с модулем проекта).

В мультимодульном проекте возникает вопрос: в каком модуле проекта создавать даггер-модули и компоненты?

 

 

Даггер-модуль

Даггер-модуль имеет смысл создавать как можно ближе к объектам, которые он будет провайдить. В нашем случае мы создаем его там, где лежит Database - в модуле data.

Во-первых, это удобно и интуитивно понятно, когда даггер-модуль и создаваемый объект находятся рядом - не надо будет бегать по проекту при каких то изменениях в создании объекта.

Во-вторых, когда даггер-модуль и Database находятся в одном модуле, они имеют одинаковые знания о других классах/модулях проекта. И если нам при создании Database будет нужен еще какой-то объект из какого-то модуля, то наш даггер-модуль точно будет знать/видеть этот объект.


В модуле data создаем даггер-модуль, который отвечает за создание Database:

DataModule (:data)

@Module
class DataModule {

   @Provides
   fun provideDatabase() =
       Database()

} 

 

 

Компонент

Переходим к компоненту. В каком модуле он должен находиться?

Давайте исходить из задач компонента. Он создает объекты и инджектит их в Activity. Для этого компонент должен находиться в модуле, из которого видны:
- Activity, в которое инджектим
- создаваемые объекты, которые инджектим

Модуль data тут явно не подходит, т.к. он знает только про свое содержимое, а про TasksAcivity из модуля app не знает. Т.е. если компонент находится в модуле data, то он сможет создать объект Database, но не сможет заинджектить его, потому что не будет знать про класс TasksActivity.

А вот модуль app для компонента вполне годится. Этот модуль знает и про объекты из модуля data (т.к. мы прописали dependencies) и про TasksActivity, куда надо инджектить. В модуле app компонент будет иметь доступ ко всем необходимым объектам.

Кроме того, есть рекомендация от гугла: компонент надо создавать в том модуле, где находится объект, куда компонент будет инджектить. Мы инджектим в TasksAcivity. Оно находится в модуле app. Значит и компонент должен быть в этом модуле.

 

Отдельный компонент под TasksActivity пока создавать не будем. Ограничимся созданием общего App компонента, который будет уметь инджектить в TasksActivity:

AppComponent (:app)

@Component(modules = [DataModule::class])
interface AppComponent {

   fun injectTasksActivity(tasksActivity: TasksActivity)

}

Не забываем предоставить компоненту даггер-модуль DataModule, чтобы компонент умел создавать Database

 

 

Инджект

Осталось создать App класс, который будет создавать и держать компонент:

App (:app)

class App: Application() {

   lateinit var appComponent: AppComponent

   override fun onCreate() {
       super.onCreate()
       appComponent = DaggerAppComponent.create()
   }
}

Не забудьте добавить App класс в манифест

 

Если класс DaggerAppComponent не создается, то включайте стандартную магию: Clean Project, Rebuild Project, Invalidate Caches и вот это вот все.

 

Все готово. Теперь мы можем использовать компонент, чтобы инджектить Database в TasksActivity:

TasksActivity (:app)

class TasksActivity : AppCompatActivity() {

   @Inject
   lateinit var database: Database

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_tasks)
       (applicationContext as App).appComponent.injectTasksActivity(this)
   }
}

Получаем класс App, берем из него компонент и выполняем инджект.

 

Схема получилась такая:

 

Сплошные стрелки показывают, что где используется. TasksActivity использует Database и компонент. 

А пунктирными стрелками я показал путь Database до компонента. Компонент использует DataModule, который создает Database. 

 

 

Результат

Мы подключили даггер к проекту и выяснили, где лучше создавать даггер-модуль и компонент.

Даггер-модуль создаем там, где лежит создаваемый объект. В нашем примере это модуль data, где лежит Database.

Компонент создаем там, где лежит объект, в который будет выполняться инджект. В нашем примере это модуль app, где лежит TasksActivity.

Это достаточно важный момент для понимания темы. Компонент и даггер-модули не обязаны находиться в одном модуле. Компонент может использовать даггер-модули из других модулей проекта. Главное, чтобы все зависимости были прописаны.

 

Кому-то тут все будет понятно и прозрачно. Но для других компонент до сих пор выглядит, как черный ящик, который творит магию.

Давайте откроем этот ящик. На следующем уроке мы создадим свою реализацию компонента AppComponent и используем ее вместо даггеровской. Так мы будем максимально понимать, что происходит под капотом.


Присоединяйтесь к нам в Telegram:

- в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance 

- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня




Комментарии   

# RE: Dagger в мультимодульном проекте. 2. Подключаем даггерЛеонид 12.07.2023 20:42
Есть бага в кнопках "Вперёд" и "Назад". При нажатии на кнопки не то действие совершают, а противоположное
# RE: Dagger в мультимодульном проекте. 2. Подключаем даггерDmitry Vinogradov 14.07.2023 14:09
Да, потому что сортировка статей в блоге по от новых к старым, и навигация работает в ту же сторону. Не нашел, как можно сделать навигацию в сторону, противоположную сортировке.

Language

Автор сайта

Дмитрий Виноградов

Подробнее можно посмотреть или почитать.

Никакие другие люди не имеют к этому сайту никакого отношения и просто занимаются плагиатом.

Социальные сети

 

В канале я публикую ссылки на интересные и полезные статьи по Android

В чате можно обсудить вопросы и проблемы, возникающие при разработке



Группа ВКонтакте



Поддержка проекта

Яндекс
410011180491924

WebMoney
R248743991365
Z551306702056

Paypal