Koin, как вводить за пределами активности Android / приложения

Koin - это новая облегченная библиотека для DI, которую можно использовать в Android как а также в автономных приложениях kotlin.

Обычно вы вводите такие зависимости:

class SplashScreenActivity : Activity() {

    val sampleClass : SampleClass by inject()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }
}

методом inject().

Но как насчет инъекций в места, где контекст Activity недоступен, то есть вне Activity?


person kosiara - Bartosz Kosarzycki    schedule 03.04.2018    source источник
comment
Вы нашли решение? Я сталкиваюсь с тем же вопросом   -  person IgorGanapolsky    schedule 28.12.2018


Ответы (3)


На помощь приходит KoinComponent. В любом классе вы можете просто:

class SampleClass : KoinComponent {

    val a : A? by inject()
    val b : B? by inject()
}

Расширение KoinComponent дает вам доступ к inject() методу.

Помните, что обычно достаточно ввести что-нибудь обычным способом:

class SampleClass(val a : A?, val b: B?)
person kosiara - Bartosz Kosarzycki    schedule 03.04.2018
comment
вы уверены, что ваши классы A и B могут иметь нулевые значения? - person Andrey Danilov; 26.04.2018
comment
Хм, я думаю, что с точки зрения KISS в таких случаях лучше использовать конструктор (чтобы не переусердствовать;)) в качестве точки инъекции. Но интересно, что мы можем расширить Koin component, чтобы разрешить инъекцию с использованием Koin. - person Patryk Jabłoński; 10.07.2018
comment
Вы хотите сказать, что нам не нужен startKoin в этом случае? - person IgorGanapolsky; 29.12.2018
comment
Имейте в виду, что KoinComponent не следует использовать, если это не является строго необходимым: еще одна вещь, которую я видел, - это неправильное использование интерфейса KoinComponent для расширения API локатора сервисов. Имейте в виду, что как пользователь фреймворка Koin вам не нужно использовать этот интерфейс. medium.com/koin- разработчики / - person laim2003; 22.12.2020

Koin предлагает решение этой проблемы с помощью интерфейса KoinComponent. Например, если вам нужно получить некоторые зависимости в вашем репозитории, вы можете просто реализовать интерфейс KoinComponent. Это дает вам доступ к различным функциям Koin, таким как get() и inject(). Используйте KoinComponent только в том случае, если вы не можете переписать конструктор, чтобы принимать зависимости в качестве параметров конструктора.

class MyRepository: Repository(), KoinComponent {
  private val myService by inject<MyService>()
}

Внедрение конструктора лучше, чем этот подход.

Например, того же можно добиться:

class MyRepository(private val service: MyService): Repository() {
    ...
}

И вы можете добавить определение для создания экземпляра этого класса в модуле коина:

val serviceModule = module {
    ...

    factory { MyService() }
}
val repositoryModule = module {
    ...

    factory { MyRepository(get<MyService>()) }
}
person harold_admin    schedule 14.04.2019
comment
Почему внедрение конструктора лучше, чем этот подход с KoinComponent? - person head01; 20.11.2019
comment
Подход с KoinComponent известен как внедрение поля. Вот несколько причин, по которым внедрение конструктора лучше: 1. Проще: ваш класс заботится только о том, какие зависимости ему нужны, а не о том, кто им удовлетворяет. 2. Более надежный: экземпляр вашего класса в согласованном состоянии сразу после его создания, а не после завершения внедрения поля. 3. Упрощение тестирования: объявление зависимостей в конструкторе упрощает предоставление их макетов во время тестирования. - person harold_admin; 21.11.2019
comment
@harold_admin хороший ответ, не могли бы вы объяснить, что такое Repository (), который мы расширяем / реализуем здесь? - person Richard Miller; 28.12.2019
comment
@Hatzil Это может быть любой базовый класс. Честно говоря, для целей этого примера это не имеет значения. Я просто хотел проиллюстрировать, что вы можете использовать Koin независимо от того, есть у вас базовый класс или нет. - person harold_admin; 29.12.2019
comment
Привет, @harold_admin, хороший ответ, все еще есть вопрос, а как насчет того, что MyRepository является объявленным манифестом широковещательным приемником? Я решил эту проблему с помощью расширения koin inject, но, может быть, есть другое решение? - person ininmm; 15.06.2020
comment
@ininmm Не уверен, правильно ли я понял. MyRepository - это широковещательный приемник или он зависит от широковещательного приемника? В первом случае я не думаю, что вы можете использовать инъекцию конструктора, потому что BroadcastReceivers создаются системой, оставляя инъекцию поля в качестве единственного варианта. - person harold_admin; 15.06.2020
comment
Да, я имею в виду, что MyRepository получен из широковещательного приемника. Вы абсолютно правы, использование полевого впрыска - единственная серебряная пуля. - person ininmm; 15.06.2020

Если вы не хотите реализовывать какие-либо интерфейсы, просто посмотрите, как _ 1_ и сделайте что-то подобное самостоятельно:

val foo by lazy { KoinPlatformTools.defaultContext().get().get<FooClass>() }
person Mark    schedule 05.02.2020
comment
Особенно полезно, если вы хотите получить доступ к чему-то, что настроено с помощью koin, из самого ApplicationClass :) - person Benjamin Mesing; 06.01.2021