Пара предположений для этой статьи:

  1. Чтобы полностью понять эту статью, читатель должен иметь хотя бы базовые знания о библиотеке Dagger 2.
  2. Для упрощения позже я буду называть библиотеку Dagger 2 просто Dagger.
  3. Я использовал здесь в качестве примера архитектуру MVP, но с любой из этих библиотек можно использовать любую другую.

Модули

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

Модуль в Dagger использует в основном аннотации для объявления своих частей (как и в других компонентах этой библиотеки). Таким образом, класс объявляется с @Module и методами для предоставления экземпляров графа зависимостей, которые отмечены аннотациями @Provides.

Конечно, это основной способ заявить об этом. Dagger - это зрелая библиотека с множеством функций, которые могут пригодиться в определенных случаях. В этой статье я не буду вдаваться в подробности каждого из них, поскольку это не является целью.

Каждый метод поставщика по умолчанию будет вызываться и создавать экземпляр объекта, который он предоставляет, каждый раз, когда мы будем вызывать Dagger для этого типа класса. Это, конечно, если мы не используем одну из аннотаций, которые сочетаются с @Provides, как @Singleton, которая создаст объект только при первом вызове, а после этого просто поделится им. Есть также аннотации областей, которые меняют это, но это будет рассмотрено позже.

Коин использует DSL (предметно-ориентированный язык, отличные статьи о Kotlin DSL). Мы объявляем наш модуль, создавая его переменную с функцией модуль. У него есть пара необязательных параметров (например, createOnStart для указания создания определения модуля с запуском Koin), но наиболее важным является definition: ModuleDefinition.() -> Unit, который представляет собой блок кода, в котором мы объявляем наших поставщиков.

Провайдеры также являются функциями, и, как и в случае с Dagger, мы можем объявить здесь, хотим ли мы создавать новый экземпляр объекта каждый раз, когда он вводится (factory {...}), или нам нужен синглтон (single {...}). Конечно, как и в Dagger, мы также можем объявить для них области действия, что ограничивает их время жизни областью действия, но это будет рассмотрено позже.

На веб-странице Koin мы можем прочитать, что они не используют прокси, генерацию кода или отражение, но это не стопроцентная правда. Они добавили функцию, которая может упростить приведенный выше пример модуля с помощью отражения.

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

Инициализация

В Dagger нам нужно инициализировать соответствующий компонент в нашем классе Application. Компоненты - это интерфейсы, на основе которых создаются соответствующие классы компонентов Dagger. Создавая, мы можем создать экземпляр этого класса и предоставить доступ всем поставщикам, которые были добавлены в модули к этому компоненту.

Koin также инициализируется в классе Application, но не требует каких-либо объявлений интерфейса Component.

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

Получение компонентов

Итак, мы описали наши модули со всеми необходимыми нам поставщиками и инициализировали отправную точку. Пришло время использовать все эти вещи.

С Dagger мы можем использовать функцию ActivityInjector, чтобы немного упростить этот процесс, объединившись с объявлением инъекции в конструкторе Presenter, мы могли бы избавиться от объявления SubComponent и Module для каждого Activity (отличный пример статьи, как это сделать).

Хорошо, но даже с ними нам нужно связать нашу Activity в ActivityBuilder, а затем вызвать Activity AndroidInjection.inject(this) в методе onCreate, чтобы иметь возможность внедрять вещи (снова с помощью аннотации) @Inject в ваш класс.

И здесь снова Koin немного проще, поскольку мы можем внедрять вещи в Activity, Fragments и Services прямо из коробки, с помощью всего одной строки:

И если вы хотите внедрить в класс что-то, что не является ни одним из этих трех (Activity, Fragment или Service), просто пометьте его интерфейсом KoinComponent и все!

Области применения

Наконец, мы вернулись к прицелам. Если вы знаете прицелы из Dagger, можете пропустить следующий абзац.

Прицелы в Dagger объявляются аннотацией (неудивительно). Но эти аннотации - это не то, что предоставляет библиотека. Пользователь объявляет, какие области он хочет (например, ActivityScope), затем создает аннотацию и аннотирует компонент, который живет в этой области. Затем добавьте эту аннотацию к выбранным компонентам, которые предоставляются для графа зависимостей, она может быть либо в модуле в методе поставщика, либо в самом классе. Эти экземпляры будут храниться как одиночные, пока жив компонент с общей аннотацией. Для получения дополнительной информации перейдите в раздел Синглтоны и привязки с оптическим прицелом в Руководстве по кинжалам.

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

Еще одно сходство заключается в том, что он определен для провайдеров в модулях, как в примере ниже.

Но способ связывания другой. Мы не привязываем его к жизни компонентов, как в Dagger. На самом деле, есть два способа определить это. Первое приемлемо только для Android LifecycleOwner.

Что по умолчанию убивает область видимости на Lifecycle.Event.ON_DESTROY, но это может быть отменено вторым параметром функции bindScope любым другим Lifecycle.Event.

Второй - для разделения области действия между компонентами (например, для совместного использования UserSession или Bucket в приложении для покупок). Так что модульная часть не меняется.

Но вам не нужно связывать его с LifecycleOwner только тогда, когда вы хотите запустить вызов области:

getKoin().createScope("session")

и когда вы хотите закончить, просто позвоните:

getKoin().getScope("session").close()

Суммировать

Есть много других функций, которые можно сравнить, например, поддержка модели ViewModel для компонентов архитектуры Android, которая есть в обеих библиотеках, но, возможно, лучше оставить это для другой статьи и сосредоточиться на общей картине этого сравнения.

Dagger основан на аннотациях и генерации кода. Он более зрелый, с множеством функций, и что-то можно делать несколькими разными способами с одинаковым хорошим результатом. Но в целом со всеми этими функциями он кажется более сложным и может напугать новичков.

Коин мне кажется проще и чище, и он не генерирует код, так что вы сэкономите время. Наверняка вы найдете случай, когда лучше использовать Dagger, но было бы просто жаль не попробовать Koin в каких-то более простых проектах, и проверьте сами, не улыбнетесь ли вы один или два раза. Он быстро пополняется новыми функциями, так что кто знает, не догонит ли он Dagger в ближайшем будущем.

Первоначально опубликовано на www.netguru.com.

📝 Прочтите этот рассказ позже в Журнале.

🗞 Просыпайтесь каждое воскресенье утром и слышите самые интересные истории, мнения и новости недели, ожидающие вас в почтовом ящике: Получите примечательный информационный бюллетень›