[Разработка под Android] Hilt еще один DI?

Автор Сообщение
news_bot ®

Стаж: 6 лет 3 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
11-Авг-2020 22:30

Встречайте Hilt — Dependency Injection (DI) в JetPack, но это не правда, так как Hilt это просто обертка для Dagger2. Для небольших проектов сможет встать более удобным инструментом и хорошо интегрируется с остальными продуктами в JetPack.
Не буду описывать как добавить в проект, все хорошо описано в статье
Зачем?
Dagger2 довольно сложный DI, можно легко запутаться, что и куда поместил. Придумывать бесконечное количество компонентов и увеличивается количество абстракций. И чем больше проект, тем больше увеличивается путаница.
И если хочется использовать Dagger2, но с минимальными усилиями, то для этого как раз и был придуман Hilt.
Что упростили для нас:
  • Готовые компоненты (из названий понятно к чему относятся)
    • ApplicationComponent
    • ActivityRetainedComponent
    • ActivityComponent
    • FragmentComponent
    • ViewComponent
    • ViewWithFragmentComponent
    • ServiceComponent
  • В модуле указываешь в какой компонент добавить
  • Через @AndroidEntryPoint Hilt компилятор генерирует весь bolierplate для создания компонента и хранения (например, ActivityRetainedComponent сохранит сущность после поворота экрана, ActivityComponent пересоздаст заново).

Такой код выглядит довольно элегантно (весь boilerplate за нас сгенерируется)
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
    @Inject lateinit var testService: TestService
}

Особенности
Application обязателен
Необходимо объявить Application и пометить @HiltAndroidApp, без него Hilt не заработает.
@HiltAndroidApp
class App : Application() { }

Иерархическая зависимость
Если хотите использовать Hilt в фрагментах, то Activity которая содержит эти фрагменты обязательно помечать аннотацией @AndroidEntryPoint
Если View пометить @WithFragmentBindings то Fragment должен быть с аннотацией @AndroidEntryPoint, а без этой аннотации зависит от того куда инжектимся Activity или Fragment
Объявление модулей
Все как в Dagger2, но нет необходимости добавлять модуль в компонент, а достаточно использовать аннотацию @InstallIn. Это и понятно, так как компоненты не доступны для редактирования.
@InstallIn(ApplicationComponent::class)
@Module
class NetworkModule {
    @Singleton
    @Provides
    fun provideHttpService(): HttpService {
        return object : HttpService {
            init {
                Log.e("Tester", "HttpService initialized")
            }
            override fun request() {
                Log.e("Tester", "HttpService::request")
            }
        }
    }
}

При добавления Hilt, все модули должны быть с @InstallIn, либо компилятор ругнется, что аннотация отсутствует.
Кастомные Component и Subcomponent
Создать их конечно можно, так как там Dagger2, но теряется тогда весь смысл Hilt и все придется писать вручную. Вот что предлагается в документации:
DaggerLoginComponent.builder()
        .context(this)
        .appDependencies(
          EntryPointsAccessors.fromApplication(
            applicationContext,
            LoginModuleDependencies::class.java
          )
        )
        .build()
        .inject(this)

Поддержка многомодульности
Все это есть, но только когда используем только готовые компоненты. Но если добавить для каждого модуля свои компоненты (как советуют тут), то лучше использовать Dagger2.
Ограничения для @AndroidEntryPoint
  • Поддерживаются Activity наследуемые от ComponentActivity и AppCompatActivity
  • Поддерживаются Fragment наследуемые от androidx.Fragment
  • Не поддерживаются Retain фрагменты

Что внутри
Hilt работает следующим образом:
  • Генерируются Dagger Component-ы
  • Генерируются базовые классы для Application, Activity, Fragment, View и т.д, которые помечены аннотацией @AndroidEntryPoint
  • Dagger компилятор генерирует статический коды

Как устроено хранение ActivityRetainedComponent
Не стали усложнять и просто поместили компонент в ViewModel из arch библиотеки:
this.viewModelProvider =
        new ViewModelProvider(
            activity,
            new ViewModelProvider.Factory() {
              @NonNull
              @Override
              @SuppressWarnings("unchecked")
              public <T extends ViewModel> T create(@NonNull Class<T> aClass) {
                ActivityRetainedComponent component =
                    ((GeneratedComponentManager<LifecycleComponentBuilderEntryPoint>)
                            activity.getApplication())
                        .generatedComponent()
                        .retainedComponentBuilder()
                        .build();
                return (T) new ActivityRetainedComponentViewModel(component);
              }
            });

Итог
Плюсы:
  • Более простое использование чем Dagger2
  • Добавление модулей через аннотацию выглядит довольно удобно (в несколько уже не поместишь)
  • Код чище и много boilerpate спрятано.
  • Все плюсы от Dagger2 (генерация статического кода, валидация зависимостей и т.д.)
  • Удобен для небольших проектов

Минусы:
  • Тяжело избавится, не только захочется убрать или заменить, но и просто перейти на Dagger2
  • Тяжело добавить кастомные компоненты, что ограничивает использование с крупных проектах
  • Наследует минусы Dagger2 и еще больше увеличивает время сборки
  • Иерархическая зависимость, например, нельзя использовать в Fragment без Activity c @AndroidEntryPoint

Полезные ссылки:

===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_razrabotka_pod_android (Разработка под Android), #_jetpack, #_androidx, #_hilt, #_dependency_injection, #_razrabotka_pod_android (
Разработка под Android
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 15-Май 21:09
Часовой пояс: UTC + 5