Кинжал 2 и зависимость от инъекций ад? - PullRequest
0 голосов
/ 25 июня 2018

Как вы используете кинжал из Kotlin?

Я был в цикле исправления одной ошибки компиляции и перехода к другой, и в конце я возвращаюсь к шагу 1

Здесьэто все, что мне нужно:

  • AppDependencies
  • GenericActivityDependencies
  • PerActivityDependency

Вот мои основные зависимости:

Приложение

@Module
class ApplicationModule(private val application: Application) {
    @Provides
    @Singleton
    fun provideContext(): Application = this.application
}

@Singleton
@Component(modules = [ HttpModule::class, ApplicationModule::class ])
interface AppComponent {
    val app: Application
}

Почему мне нужно один раз предоставить зависимость в модуле, а другой раз определить ее в компоненте?

Модуль активности

@Module
class ActivityModule(private val activity: Activity) {

    @PerActivity
    @Provides
    @ActivityContext
    fun provideContext(): Context = activity
}

@Component(modules = [ActivityModule::class], dependencies = [AppComponent::class])
@ActivityContext
interface ActivityComponent {
    fun inject(activity: MainActivity)
}

HomeModule

@Module
class LandingModule {
    @PerActivity
    @Provides
    fun provideSomethig(): Something {
        return  Something()
    }
}
@SomeActivity
@Subcomponent(modules = [LandingModule::class])
interface LandingSubcomponent {
    val something: Something
}

К этому моменту я написал больше кода, чем необходимо для всей моей деятельности.

  • Я получаю ошибки, которые не могут быть унаследованы от компонента областей действия
  • Не удается сгенерировать генкод Dagger
  • Субкомпоненту нужна другая область действия

Как мне этого добиться?

Есть ли лучший di для kotlin?

Есть ли где-нибудь образец, который я мог бы использовать для каждого модуля активности?

Ответы [ 2 ]

0 голосов
/ 25 июня 2018

Я понимаю твои разочарования.Я был там раньше, и мне потребовалось довольно много времени, чтобы понять сам кинжал.Просто быстрая демонстрация / учебник.

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
    fun context(): Context
}

@Module
class AppModule(private val application: Application) {
    @Provides
    @Singleton
    fun provideApplication(): Application= application
}

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

Почему, черт возьми, мне нужно один раз предоставить зависимость в модуле, а в другой раз определить ее в компоненте.Это просто глупо.

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

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
    fun inject(activity: MainActivity)
}

Здесь вы ничего не выставляете, но вы все равно можете получить контекст действия из контейнера через инъекцию.

Теперь давайте перейдем к определению области.

Scoping - это способ предоставления «локальных синглетонов» внутри вашего контейнера.Зависимость по объему будет создана только один раз внутри контейнера.Примером является ваша область действия PerActivity.Компонент с областью действия принимает только модуль с той же областью действия.Например:

@PerActivity
@Component(dependencies = [AppComponent::class],
        modules = [ActivityModule::class])
interface ActivityComponent{
    fun inject(activity: MainActivity)
}

Соответствующий модуль должен быть ограничен только PerActivity.

class ActivityModule(activity:Activity) {
    @PerActivity
    @Provides
    fun provideActivity() = activity
}

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

Что касается зависимостей компонентов, вы можете использовать dependencies или subcomponents.Если используются зависимости, любая зависимость, которая требуется дочернему элементу, должна быть раскрыта родителем.В нашем случае выше, если ActivityComponent требует контекста активности, AppComponent должен определить функцию, которая его возвращает.В подкомпонентах просто укажите свой подкомпонент в своем компоненте, и зависимости будут разрешены внутри.

Я написал небольшое руководство по изучению кинжала 2. Если вам интересно, вы можете проверить его.https://medium.com/tompee/android-dependency-injection-using-dagger-2-530aa21961b4 https://medium.com/tompee/dagger-2-scopes-and-subcomponents-d54d58511781

0 голосов
/ 25 июня 2018

Почему, черт возьми, мне нужно один раз предоставить зависимость в модуле, а в другой раз определить ее в компоненте.Это просто глупо.

Я согласен, но не обескураживайтесь этим фактом, потому что, как только вы научитесь овладевать им, вы научитесь ценить его и действительно использовать в своих интересах.Я пользуюсь версией 2.2 без проблем.Мне нужно было только определить одну аннотацию, добавить пару дополнительных зависимостей (среди них AutoDagger, который заботится об этой компонентной функции ) и использовать следующую структуру:

/*   Dagger   */
implementation "com.google.dagger:dagger:2.2"
// Fix: github.com/rharter/auto-value-gson/issues/43#issuecomment-219994018
kapt 'com.squareup:javapoet:1.9.0'
kapt "com.google.dagger:dagger-compiler:2.2"
compileOnly 'org.glassfish:javax.annotation:10.0-b28'

/*  Autodagger   */
kapt "com.github.lukaspili.autodagger2:autodagger2-compiler:1.1"
implementation "com.github.lukaspili.autodagger2:autodagger2:1.1"

DaggerScope.java

@Retention(RetentionPolicy.RUNTIME)
@Scope
@interface DaggerScope {
}

YourApp.kt

@AutoComponent(modules = [YourApp.Module::class])
@AutoInjector
@DaggerScope
class YourApp : Application() {
    ...

    @Singleton @dagger.Module
    inner class Module(private val app : YourApp) {
        @Provides @AutoExpose(YourApp::class) fun application(): Application = app
        @Provides @AutoExpose(YourApp::class) fun context(): Context = app
        ...
        // Stuff like your database or base service can go here
    }
}

SomeActivity.kt

@AutoComponent(dependencies = [YourApp::class],
        modules = [SomeActivity.Module::class])  // you are free to add other modules here
@AutoInjector
@DaggerScope
class SomeActivity : AppCompatActivity() {
    ...
    @dagger.Module
    inner class Module() {
         @Provides @AutoExpose(SomeActivity::class) fun something(): Something {
               return some way of creating Something
         }
         /*  specific deps for SomeAcitivity's actions, like specific services. 
             You can also access DAOs as you've got access to the DB   */
    }
}

Вы также можете имитировать эту структуру с помощью Fragment вместо Activity.

Надеюсь, это поможет вам!

...