Q:

dagger2, how can i call @BindsInstance denoted method of SubComponent..?

please help me! I have a trouble in use of dagger 2. 
I want to bind some dependency in runtime not in compile time inside MainActivity by using @Subcomponent.Builder and @BindsInstance
I have an ApplicationComponent and it has a Builder and its @BindsInstance looks working fine. I can use like below
DaggerApplicationComponent
    .builder()
    .application(this)
    .build()
    .inject(this)

but some trouble came from MainActivity...
below are snippets of codes
[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))
    }

}

The problem is that I cannot access DaggerMainComponent because the Dagger doesn't generate it automatically.
I am searching for lots of websites to solve this but failed.
Is there any way to make it?   

A:

I have found a way to achieve what you want, I think. Apologies for not using your particular example, but it was easier to paste in the code I have and know that works from my own IDE. I've added comments on the critical lines. Here's the code:
Singleton component
@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
  }
}

This binding code is essentially identical to yours.
@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)
  }
}

It is critically important to note that the subcomponent which you generate in this way doesn't get magically stored somewhere by dagger. If you want your late-bound instance to be available for injecting into other classes controlled by your @PerActivity scope, you need to manually manage the lifecycle of this subcomponent. Store it somewhere (maybe in your custom Application class), and then you also must set its reference to null when your activity is destroyed, or you'll be leaking that activity.

