dagger2, как я могу вызвать @BindsInstance обозначенный метод SubComponent ..? - PullRequest
0 голосов
/ 13 июня 2018

пожалуйста, помогите мне!У меня проблема с использованием кинжала 2.

Я хочу связать некоторую зависимость во время выполнения, а не во время компиляции внутри MainActivity, используя @Subcomponent.Builder и @BindsInstance

У меня естьApplicationComponent и он имеет Builder, и его @BindsInstance выглядит нормально.Я могу использовать, как показано ниже

DaggerApplicationComponent
    .builder()
    .application(this)
    .build()
    .inject(this)

, но некоторые неполадки возникли из MainActivity ...

ниже приведены фрагменты кодов

[ApplicationComponent]

@Singleton
@Component(modules = [ApplicationModule::class])
internal interface ApplicationComponent : AndroidInjector<MyApplication> {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: Application): Builder
        fun build(): ApplicationComponent
    }
}

[ApplicationModule]

@Module(
        includes = [
            AndroidInjectionModule::class,
            AndroidSupportInjectionModule::class,
            ActivityInjectionModule::class
        ],
        subcomponents = [
            MainComponent::class
        ]
)
internal abstract class ApplicationModule {

    @PerActivity
    @ContributesAndroidInjector(modules = [SplashModule::class])
    abstract fun splashActivity(): SplashActivity

    @Binds
    @IntoMap
    @ActivityKey(MainActivity::class)
    abstract fun mainActivity(builder: MainComponent.Builder): AndroidInjector.Factory<out Activity>

}

[MainComponent]

@PerActivity
@Subcomponent(modules = [MainModule::class])
internal interface MainComponent : AndroidInjector<MainActivity> {
    @Subcomponent.Builder
    abstract class Builder : AndroidInjector.Builder<MainActivity>()  {
        @BindsInstance
        abstract fun testClass(mainTestClass: MainTestClass): Builder
    }
}

[MainActivity]

internal class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
//        This works find without runtime injection
//        AndroidInjection.inject(this)

        /**
         *I want to bind some dependency(in this case, MainTestClass) in runtime like below.
         * so that I can use MainTestClass inside MainModule to inject this to other classes.
         * but, for some reason,
         * DaggerMainComponent IS NOT GENERATED AUTOMATICALLY...
         */
        DaggerMainComponent.builder()
                .testClass(MainTestClass())
                .build()
                .inject(this);

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        startActivity(Intent(this, SplashActivity::class.java))
    }

}

Проблема заключается в том, что я не могу получить доступ к DaggerMainComponent, поскольку кинжал нене генерировать это автоматически.Я ищу много сайтов, чтобы решить эту проблему, но не удалось.Есть ли способ сделать это?

1 Ответ

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

Я нашел способ добиться того, чего ты хочешь, я думаю.Извиняюсь за то, что не использовал ваш конкретный пример, но было легче вставить код, который у меня есть, и я знаю, что он работает из моей собственной IDE.Я добавил комментарии на критические строки.Вот код:

Синглтон-компонент

@Singleton
@Component(modules = [
  AndroidSupportInjectionModule::class,
  RuntimeBindingModule::class // my addition!
])
interface MainApplicationComponent {

  fun inject(app: MainApplication)

  // my addition!
  fun runtimeBuilder(): RuntimeBindingActivitySubcomponent.Builder

  @Component.Builder
  interface Builder {
    fun build(): MainApplicationComponent
    @BindsInstance fun app(app: Context): Builder
  }
}

Этот код привязки практически идентичен вашему.

@Subcomponent
interface RuntimeBindingSubcomponent : AndroidInjector<RuntimeBindingActivity> {
  @Subcomponent.Builder
  abstract class Builder : AndroidInjector.Builder<RuntimeBindingActivity>() {
    @BindsInstance abstract fun bindInt(intVal: Int): Builder
  }
}

@Module(subcomponents = [RuntimeBindingSubcomponent::class])
abstract class RuntimeBindingActivityModule {
  @Binds @IntoMap @ActivityKey(RuntimeBindingActivity::class)
  abstract fun bindInjectorFactory(
    builder: RuntimeBindingActivitySubcomponent.Builder
  ): AndroidInjector.Factory<out Activity>
}

MainApplication

open class MainApplication : Application(), HasActivityInjector {

  // This needs to be accessible to your Activities
  lateinit var component: MainApplication.MainApplicationComponent

  override fun onCreate() {
    super.onCreate()
    initDagger()
  }

  private fun initDagger() {
    component = DaggerMainApplicationComponent.builder()
      .app(this)
      .build()
    component.inject(this)
  }
}

RuntimeBindingActivity

class RuntimeBindingActivity : AppCompatActivity() {

  // I had to use @set:Inject because this is a primitive and we can't use lateinit 
  // on primitives. But for your case, 
  // `@Inject lateinit var mainTestClass: MainTestClass` would be fine
  @set:Inject var intVal: Int = -1

  override fun onCreate(savedInstanceState: Bundle?) {
    // And this is how you can get runtime binding
    val subComponent = (application as MainApplication).component.runtimeBuilder()
    with(subComponent) {
      seedInstance(this@RuntimeBindingActivity)
      bindInt(10) // runtime binding
      build()
    }.inject(this)

    Log.d("RuntimeBindingActivity", "intVal = $intVal")

    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_runtime_binding)
  }
}

критически важно отметить, что подкомпонент, который выСгенерировать таким образом не будет волшебным образом где-то храниться кинжалом.Если вы хотите, чтобы экземпляр с поздней привязкой был доступен для внедрения в другие классы, контролируемые вашей областью действия @PerActivity, вам необходимо вручную управлять жизненным циклом этого подкомпонента.Сохраните его где-нибудь (может быть, в своем пользовательском классе Application), и затем вы также должны установить его ссылку на null, когда ваша активность будет уничтожена, или вы будете пропускать эту активность.

...