Релиз Koin 1.0.0✨
Oct 7, 2018 · 5 min read
Так, так, так… вот оно! Уважаемые пользователи Koin, настал момент релиза нашей первой стабильной версии Koin. Спустя чуть больше года после начальной версии, мы вернулись с крутыми фичами, которые упростят процесс разработки на Kotlin и внедрение зависимостей. Поехали. 👉
Установка Koin
Версия Koin 1.0.0 доступна на Jcenter. Как обычно, обновите свой скрипт Gradle, указав новый номер версии. Ниже представлен полный список проектов Koin:
Ссылка на гайд по установке с помощью Gradle.
Koin DSL👍
Koin это первый D S L фреймворк для внедрения зависимостей. Для объявления компонентов, вам нужно знать всего 4 слова:
single и factory ключевые слова, которые помогают построить компонент с помощью лямбда-выражения. В этом выражении можно использовать функцию get() для получения необходимой зависимости из контейнера Koin.
Мы создаём Koin «модули» и объявляем «single» или «factory» экземпляры определений, вот и всё. Ниже, простой пример Koin модуля с использованием Koin 1.0:
Модули ― определение пространства имён и видимости😎
Модуль позволяет использовать ваши определения, а также сделать логическое разделение между определениями (пространством имён) и ограничить их видимость.
Во фрагменте кода, представленном ниже, ComponentB и ComponentC будут видеть только определение ComponentA из их модуля. Если нам нужно запросить экземпляр ComponentA, мы должны использовать его имя (иначе, Koin не сможет выбрать из двух определений).
По умолчанию, Koin именует каждый компонент в зависимости от пространства имён модуля. В начале у нас будет два экземпляра типа ComponentA : ComponentB.ComponentA и ComponentC.ComponentA.
Ниже показано, как мы можем получить эти экземпляры:
Для определений и модулей, у нас есть два флага, чтобы задать дополнительное поведение:
В главе «modules» из справочной документации, можно узнать об этом поподробнее.
Новый Scope API⭐️
В предыдущей версии Koin, функция release() помогала высвобождать экземпляры из пути. Это было очень неявно и действительно очень полезно.
В Koin 1.0 появился Scope API. Как это работает? Scope — это фиксированная продолжительность времени, в течение которого существует объект. После истечения этого времени, объекты под влиянием scope не могут быть внедрены снова (они выбрасываются из контейнера).
Scope обозначен собственным идентификатором ― scope id. Чтобы разрешить scope определение, вам нужно создать ассоциированный scope с этим id. Однажды созданное, разрешение будет выполнено в отношении scopeId, указанному в DSL.
Scope API будет полезен для написания компонентов с ограниченным временем жизни (сессии аутентификации, кошельки, корзины…).
Параметры внедрения✨
API для внедрения зависимостей, позволяет использовать деструктурированное объявление Kotlin напрямую, чтобы описать значения параметров, для их внедрения на лету:
Для запроса экземпляра используйте функцию parametersOf(), чтобы указать, какие параметры нужно предоставить.
Документация по параметрам внедрения, доступна по ссылке.
Лучшие объявления определений☢️
Может показаться что Koin DSL недостаточно автоматизирован, потому что приходиться писать в конструкторах вручную, с функцией get.
Если у вас есть класс реализации, для согласования с интерфейсом используйте ключевое слово singleBy. Допускается два типа параметров: singleBy ().
Все эти ключи, всё ещё экспериментальные (и используют интроспекцию, чтобы получить конструктор вашего класса). Нам нужен ваш фидбэк по этому поводу😉
Они находятся в проекте koin-core-ext (краткая справка).
Koin для Java разработчиков🌈
Большое событие: появление проекта koin-java. Идея проекта в том, чтобы создать условия для простого старта и внедрения в Java, с помощью статических хелперов:
и мощный функционал для Android💪
Много было сделано для работы с Android! Проекты были переименованы, благодаря их функционалу. Теперь у нас есть следующие Android проекты:
Мы отказались от koin-android-architecture и koin-androidx.
Фича ViewModel в Koin, предоставляется проектом koin-android-viewmodel и преследует ту же цель: облегчить внедрение зависимостей для компонентов Android Architecture ViewModel.
Объявляйте класс ViewModel с помощью ключевого слова viewModel (доступно в формате API билдера, чтобы не писать конструктор). Используйте это в Activity или Fragment с помощью by viewModel() или getViewModel().
AndroidX Ready✅
Для тех, кто хочет протестировать новую package-систему Android, мы подготовили версию проектов для AndroidX. Вот они:
Функции те же, что и в стандартном пакете, но с новыми пакетами AndroidX.
Прочие изменения⚙️
Для koin-ktor и koin-spark теперь можно использовать koin-logger-slf4j логгер, чтобы облегчить себе логирование, с предпочитаемой имплементацией (logback, log4j …).
Переход с версии Koin 0.9.x😱
Для тех, кто переходит со старой версии Koin, у нас есть страничка с помощью: https://insert-koin.io/docs/1.0/quick-references/upgrade/
Проекты для начала работы. На Github🚀
Все проекты, чтобы начать работу, доступны на Github. Их можно скачать архивом здесь.
👉 Rendez-vous @ insert-koin.io
Доступна новая версия сайта, с большими разделами:
Не Dagger’ом едины
Что такое KOIN?
Koin — это небольшая библиотека для написания внедрений зависимостей. Без прокси, кодогенерации и интроинспекции (introspection). Работает как Service Locator. Использует DSL и фичи языка Kotlin. Сама библиотека подразумевает, что будет использоваться в приложениях написанные на Kotlin, но можно и с Java.
Посмотрим как его можно использовать в проекте. Для начала надо реализовать модуль и все зависимости.
Рассмотрим, что же есть в Koin DSL.
applicationContext — Это лямбда для создание Koin модуля. Эта функция возвращает модуль Koin и является началом каждого определения компонента в Koin.
factory — Предоставление зависимости как фабричный компонент, т.е. создает каждый раз новый экземпляр.
bean — Предоставление зависимости как Singleton.
bind — Дополнительное связывание типа Kotlin для данного определения компонента.
get — Разрешает компонентные зависимости. Функция сама поймет какая зависимость требуется для каждого класса.
context — Обьявление логического контекста.
viewModel — Специальное предоставление зависимости для ViewModel, находится в отдельном пакете compile «org.koin:koin-android-architecture:$koin_version»
В конкретном примере мы работаем с архитектурными компонентами и используем ViewModel в проекте. У нас есть потребность инжектить IUserRepository во ViewModel. Koin позволяет довольно просто доставлять зависимости через конструктор во ViewModel.
Модуль необходимо будет запустить с помощью функции startKoin() в классе Application().
По факту этого уже нам хватит, чтобы использовать viewmodel в различных фрагментах и активити.
К тому же, используя by inject(), у нас происходит ленивая инициализация компонента.
Если мы против ленивых вещей, тогда можем сделать инициализировать напрямую:
Если вдруг вам надо поделиться своей ViewModel с Acitivity/Fragment, тогда можно использовать sharedViewModel(). В этот момет Acitivity или Fragment будут иметь один и тот же экземпляр MySharedViewModel.
Бывают случаи когда надо делать инжект например в кастомное вью, здесь вам поможет Koin Components. Достаточно отнаследоваться от KoinComponent и появится возможность использовать by inject<>(). На данный момент это не требуется в следующих классах: `Application`,`Context`, `Activity`, `Fragment`, `Service.
Для ViewMode ничего особенного, просто получаем необходимые зависимости в конструкторе.
Тесты
Тут все просто, надо тестовый класс наследовать от KoinTest и появляется возможность инжектить прямо в тестовый класс.
Логирование.
Ошибки Koin будет выкидавать в runtime. Так что тестировать необходимо все.
В процессе дебага Koin делает логгирование и в случае ошибки кидает вполне понятный stacktrace:
Koin — библиотека для внедрения зависимостей, написанная на чистом Kotlin
Как управлять внедрением зависимостей с помощью механизма временной области (scope)
Для будущих студентов курса «Android Developer. Professional» подготовили перевод полезной статьи.
Также приглашаем принять участие в открытом вебинаре на тему «Пишем Gradle plugin»
О чем эта статья
Вы узнаете, как с помощью модулей Koin ограничивать область живучести зависимостей, относящихся к конкретному компоненту. Вы также познакомитесь со стандартными областями Koin и способами работы с настраиваемыми областями.
Введение
Разработчики ОС Android не рекомендуют использовать внедрение зависимостей (Dependency Injection, DI (англ.)), если в вашем приложении три экрана или меньше. Но если их больше, лучше применить DI.
Популярный способ реализации DI в Android-приложениях основан на фреймворке Dagger. Но он требует глубокого изучения. Одна из лучших альтернатив этому фреймворку — Koin, библиотека, написанная на чистом Kotlin.
Если вы уже пользовались Dagger или любой другой библиотекой для DI, то, скорее всего, знаете, насколько важен в этом процессе механизм временной области (scope). Он позволяет определять, в каких случаях нужно получать один и тот же зависимый объект, а в каких — новый. Он также помогает освобождать невостребованные ресурсы и память.
Области в Koin
Концепция области в Koin аналогична таковой в Android. Она позволяет, например, ограничить область живучести модели представления (ViewModel) до определенной активности и использовать эту модель во фрагментах, которыми наполняется активность.
Как правило, в Koin три вида временных областей.
single (одиночный объект) — создается объект, который сохраняется в течение всего периода существования контейнера (аналогично синглтону);
factory (фабрика объектов) — каждый раз создается новый объект, без сохранения в контейнере (совместное использование невозможно);
scoped (объект в области) — создается объект, который сохраняется в рамках периода существования связанной временной области.
Одиночный объект(single). Фабрика объектов(factory)
Область вида single при каждом запросе возвращает один и тот же экземпляр, а factory каждый раз возвращает новый экземпляр.
Настраиваемая область
Стандартные области single и factory в Koin живут в течение жизненного цикла модулей Koin. Однако в реальных сценариях использования требования к внедрению зависимостей будут отличаться.
Зависимости обычно нужны только на определенный период времени. Например, репозиторий OnBoardRepository в Android-приложении требуется только при регистрации пользователя. Как только пользователь авторизуется, удержание этого репозитория в памяти станет лишней тратой ресурсов.
Чтобы добиться нужного поведения в Koin, можно воспользоваться API для работы с временными областями. В модуле Koin можно создать область со строковым квалификатором и объявить зависимости внутри нее с помощью уникальных квалификаторов. Давайте сделаем это шаг за шагом.
Шаг 1
Шаг 2
Следующим шагом объявим необходимые зависимости с использованием областей single и factory в соответствии с требованиями проекта. Ключевой момент заключается в присвоении областям уникальных квалификаторов. Вот так:
Шаг 3
Мы закончили настройку в модуле Koin. На этом шаге нам нужно создать область из того компонента, из которого мы импортируем нужные зависимости. Обычно области создаются из Android-компонентов, например Activity, Fragment и т. п.
Чтобы создать область, сначала нам нужно получить существующий экземпляр компонента Koin, а затем вызвать функцию createScope, передав ей идентификатор и имя области.
Получив CustomScope как значение параметра имени, Koin будет искать область, которую мы объявили под этим именем в модулях Koin. ScopeNameID — это идентификатор, который мы применяем, чтобы отличать одну область от другой. Он используется на внутреннем уровне в качестве ключа для поиска этой области.
Шаг 4
Наконец, создаем экземпляр зависимости, которую хотим использовать. Мы сделали это с помощью созданной нами области. Вот что получилось.
scopedName и factoryName — это квалификаторы, которые мы объявили внутри модуля Koin на шаге 2.
Шаг 5
Koin-Android
Выше описан общий подход к ограничению живучести зависимостей определенной временной областью. Его можно применять на любой платформе, поддерживаемой Koin. Будучи Android-разработчиком, теперь я бы хотел совместить механизмы области Koin и области жизненного цикла, чтобы свести к минимуму работу, которую мне приходится делать при каждом создании активности.
Для этого необходимо импортировать библиотеки Koin-Android. Добавьте следующие строки в узел dependencies файла build.gradle уровня приложения:
Для начала необходимо создать в модуле Koin область для зависимостей с компонентами Android. Как это сделать:
scoping dependency with android activity
Затем нужно выполнить внедрение зависимости в активности при помощи lifecyclescope :
Это позволит закрывать область при уничтожении активности, избавив нас от ручных операций. Вот так выглядит наш код:
Такой подход позволит автоматизировать работу по созданию областей, назначению квалификаторов и уничтожению областей. Кажется, что это простые действия, их можно выполнить и вручную. Но повторяющуюся работу важно автоматизировать, и по мере развития приложения это становится очевидно.
Дополнительные материалы
Подробнее о внедрении зависимостей читайте в другой статье о библиотеке Koin.
На этом все. Надеюсь, вы узнали что-то полезное для себя. Спасибо за внимание!
Подробнее о курсе «Android Developer. Professional». Записаться на открытый урок «Пишем Gradle plugin» можно здесь.
Чем отличаются Dagger, Hilt и Koin под капотом?
Привет, Хабр. Для будущих студентов курса «Android Developer. Professional» подготовили традиционный перевод материала.
Также приглашаем всех желающих на вебинар по теме «Профилируем и ускоряем Gradle сборки». На занятии участники вместе с экспертом:
— научатся искать узкие места в сборках с помощью gradle-profiler, scan и visualVM;
— научатся правильно конфигурировать Gradle;
— рассмотрят другие возможности для оптимизации и ускорения сборок на большом проекте.
Dagger и Koin, без сомнения, являются двумя самыми популярными фреймворками для внедрения зависимостей на Android. Обе эти библиотеки служат одной цели и кажутся очень похожими, но работают они по-разному.
А при чем здесь Hilt? Hilt — это библиотека, которая использует Dagger под капотом и просто упрощает работу с ним, поэтому все, что я говорю здесь о Dagger, применимо и к Hilt.
В этой статье я не буду подталкивать вас к решению, какую из этих библиотек выбрать. Вместо этого я хочу показать вам, чем они отличаются внутри, и каковы могут быть последствия от этих различий для вашего приложения.
Dagger
Если мы хотим, чтобы Dagger предоставил экземпляр какого-либо класса, все, что нам нужно сделать, это добавить аннотацию @Inject к конструктору.
Фрагмент кода, сгенерированного Dagger
Что, если мы будем использовать Hilt вместо Dagger?
В этом примере особой разницы вы бы не заметили. Hilt — это библиотека, которая использует Dagger внутри себя, а класс, который я вам показал, генерируется Dagger. Если вы используете Hilt, он создает для нас пару дополнительных классов, которые упрощают использование Dagger и сокращают количество шаблонного кода, который нам нужно написать. Но основная часть остается прежней.
У Koin совершенно другой подход к управлению зависимостями, чем у Dagger и, конечно, чем у Hilt. Чтобы зарегистрировать зависимость в Koin, мы не используем никаких аннотаций, поскольку Koin не генерирует никакого кода. Вместо этого мы должны предоставить модули с фабриками, которые будут использоваться для создания экземпляров каждого класса, который понадобится в нашем проекте.
Ключ в этой map — это полное имя класса или имя, которое мы предоставили, используя именованный параметр. Значение — это написанная нами фабрика, которая будет использоваться для создания экземпляра класса.
Какие последствия для приложения?
Есть некоторые последствия того факта, что Dagger генерирует код для предоставления зависимостей, а Koin — нет.
1. Обработка ошибок
Поскольку Dagger — это среда внедрения зависимостей во время компиляции, если мы забыли предоставить какую-либо зависимость, мы узнаем о нашей ошибке практически мгновенно, потому что наш проект не будет собран.
Например, если мы забыли добавить аннотацию @Inject к конструктору CompositeAdapter и попытаемся внедрить его во фрагмент, сборка завершится неудачно с соответствующей ошибкой, которая показывает нам, что именно пошло не так.
Вывод сборки Dagger с отсутствующей аннотацией @Inject
Koin выдает исключение, когда отсутствует фабрика для CompositeAdapter
2. Влияние на время сборки
В том, что Koin не генерирует никакого кода, есть некоторое преимущество: это оказывает гораздо меньшее влияние на время сборки. Dagger необходимо использовать процессор аннотаций для сканирования нашего кода и создания соответствующих классов. Это может занять некоторое время и замедлить нашу сборку.
3. Влияние на производительность во время выполнения
С другой стороны, поскольку Koin разрешает зависимости во время выполнения, это результирует в немного более худшей производительности во время выполнения.
На сколько? Чтобы оценить разницу в производительности, мы можем взглянуть на этот репозиторий, где Рафа Васкес измерил и сравнил производительность этих двух библиотек на разных устройствах. Тестовые данные были подготовлены таким образом, чтобы имитировать несколько уровней транзитивных зависимостей, т.е. это не просто приложение-болванка с 4 классами.
Источник: https://github.com/Sloy/android-dependency-injection-performance
Как видите, Dagger практически не влияет на производительность при запуске. С другой стороны, в Koin мы видим, что настройка занимает значительное время. Внедрение зависимостей в Dagger также немного быстрее, чем в Koin.
Резюме
Как я сказала в начале этой статьи, моя цель не в том, чтобы указать вам, какую из этих библиотек использовать. Я использовала Koin и Dagger в двух разных, довольно больших проектах. Честно говоря, я думаю, что решение, какой из них выбрать, Dagger или Koin, гораздо менее важно, чем буквально что-угодно, что позволяет вам писать чистый, простой и легкий для модульного тестирования код. И я думаю, что все эти библиотеки: Koin, Dagger и Hilt действительно служат этой цели.
У всех этих библиотек есть свои сильные стороны, и я надеюсь, что знание того, как они работают, поможет вам принять решение, какая из них лучше всего подойдет именно для вашего приложения.
Koin – это Dependency Injection или Service Locator?
В Android-разработке для DI традиционно используют Dagger 2, очень мощный фреймворк с кодогенерацией. Но есть проблема: новичкам сложно его использовать. Сами принципы DI просты и понятны, но Dagger усложняет их. Можно жаловаться на поголовное падение грамотности программистов, но от этого проблема не исчезнет.
С появлением Kotlin появилась возможность писать удобные вещи, которые были бы практически невозможны с использованием Java. Одной из таких вещей стал Koin, который является не DI, а Service Locator, который многими трактуется как anti-pattern, из-за чего многие принципиально его не используют. А зря, ведь у него очень лаконичный API, упрощающий написание и поддержку кода.
В данной статье я хочу помочь новичкам разобраться с разграничением понятий Dependency Injection и Service Locator, но не с самим Koin.
Dependency Injection
Если переписать класс Car с использованием подхода DI, то может получиться вот это:
Service Locator
Попробуем разобраться с Service Locator. Тут тоже ничего сложного – это некий реестр, который по запросу может предоставить нужный объект. Пока я предлагаю отойти в сторону от Koin и представить некий абстрактный ServiceLocator, без деталей реализации, но с простым и понятным API.
У нас есть возможность добавить в наш реестр некую зависимость, а также получить эту зависимость. Вот пример использования с нашими двигателями и машинами:
Теперь мы знаем, что у Car есть зависимости, но всё ещё не знаем какие. Т.е. это не решение нашей проблемы. Но есть ещё один вариант:
Это и есть Dependency Injection в чистом виде. С Koin это бы выглядело вот так:
Увы, нам всё ещё необходимо обращаться к Koin для получения зависимостей, но это никоим образом не противоречит принципам Dependency Injection.
UPDATE. По просьбе kranid приведу максимально простой пример на Dagger 2.






