请帮帮我!我在使用匕首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,因为Dagger不会自动生成它。 我正在寻找很多网站来解决这个问题,但都失败了。 有什么方法可以做到吗?
答案 0 :(得分:2)
我认为,我已经找到了实现目标的方法。抱歉没有使用您的特定示例,但更容易粘贴到我拥有的代码中,并且知道它可以在我自己的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
范围控制的其他类,则需要手动管理此子组件的生命周期。将它存储在某个地方(可能在您的自定义应用程序类中),然后您还必须在活动被销毁时将其引用设置为null
,否则您将泄露该活动。