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

 

Мы решаем еще раз поменять реализацию Database. И теперь нам для базы данных понадобилась работа с файлами.

Под это мы создаем новый модуль core, и в нем - новый класс FileManager.
FileManager.kt (:core)

class FileManager {
}

 

А также добавляем даггер-модуль, который будет отвечать за создание объекта FileManager:

CoreModule.kt (:core)

@Module
class CoreModule {

   @Provides
   fun provideFileManager() =
       FileManager()

}

 

Попробуем использовать FileManager в классе Database:

Database.kt (:data)

class Database(
   private val context: Context,
   private val fileManager: FileManager
) {
}

Такой код выдаст ошибку, т.к. модуль data не знает про core, а значит классы модуля data не знают про классы модуля core.

 

Схема модулей: 

 

Чтобы это исправить, пропишем зависимость data от core

build.gradle (:data)

implementation project(path: ':core')

 

Схема модулей:

 

Теперь класс Database из модуля data увидит и сможет использовать класс FileManager из модуля core.

Подправим даггер-модуль DataModule (он теперь тоже видит и может работать с FileManager):

DataModule (:data)

@Module
class DataModule {

   @Provides
   fun provideDatabase(context: Context, fileManager: FileManager) =
       Database(context, fileManager)

}

Метод provideDatabase получает FileManager и использует его, чтобы создать Database.

 

Схема объектов:

Чтобы разгрузить эту схему, я убрал из нее даггер-модули.

На первый взгляд все ок. TasksActivity (из app) использует Database (из data), который использует FileManager (из core).

 

Но в этой схеме есть проблема, которая может быть не сразу заметна. Чтобы явно ее увидеть, давайте попробуем создать объект Database в нашем компоненте:

MyAppComponent (:app)

Чтобы компонент смог создать Database, он должен в метод provideDatabase передать объект FileManager. Но в модуле app мы ничего не знаем про FileManager, потому что модуль app не знает про core.

Это важный для понимания момент. Если app знает про data, а data знает про core, это не значит, что app знает про core.

Это правило действует, если мы используем implementation, когда объявляем зависимости модулей. Но есть и другие варианты. Можно зависимость модуля data от модуля core оформить так:

build.gradle (:data)

api project(path: ':core')

Вместо implementation мы можем использовать api. В этом случае все модули, знающие про модуль data, автоматически будут знать и про модуль core. Но это тема для отдельной статьи, там свои плюсы, минусы и подводные камни. Я буду использовать только implementation зависимости.


Чтобы компонент смог работать с FileManager, нам надо добавлять зависимость app от core:

build.gradle (:app)

implementation project(path: ':core')

 

Схема модулей:

Добавилась зависимость app от core.

 

Теперь мы можем в интерфейс компонента добавить CoreModule:

AppComponent (:app)

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

   fun injectTasksActivity(tasksActivity: TasksActivity)

}

Компонент даггера будет знать, где ему взять FileManager

 

Наш компонент тоже надо этому научить:

MyAppComponent (:app)

class MyAppComponent(private val context: Context): AppComponent {

   private val dataModule = DataModule()
   private val coreModule = CoreModule()

   override fun injectTasksActivity(tasksActivity: TasksActivity) {
       tasksActivity.database =
           dataModule.provideDatabase(context, coreModule.provideFileManager())
   }

}

Используем CoreModule для получения FileManager и создаем Database.

 

 

Результат

Мы создали новый модуль core с объектом FileManager, который нужен при создании Database. Очевидно, что при этом нам пришлось добавить зависимость data от core.

Но не совсем очевидно, почему нам пришлось добавить еще и зависимость app от core. Ведь TasksActivity не надо было ничего знать про FileManager, ему хватало Database.

Схема объектов:

На схеме видно, что компонент использует и класс Database из data и класс FileManager из core, чтобы создать объект Database. Поэтому app у нас должен знать про оба этих модуля.

Возможно, возникает мысль, что DataModule мог бы сам использовать CoreModule, чтобы создать FileManager. Но так это не работает. Даггер-модули не используют друг друга. Компонент - это единый центр, который использует все доступные ему даггер-модули, чтобы создавать объекты.

В итоге из-за компонента нам пришлось добавить зависимость модуля app от core. А вот если бы TasksActivity у нас находилось в отдельном модуле, то этому модулю хватило бы зависимости только от модуля data.

В следующем уроке попробуем вынести TasksActivity в отдельный модуль.


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

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

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

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

- новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме 




Language

Автор сайта

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

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

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

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

 

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

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



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



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

Яндекс
410011180491924

WebMoney
R248743991365
Z551306702056

Paypal