android - dagger2,我如何调用 SubComponent 的 @BindsInstance 表示方法..?
问题描述
请帮我!我在使用匕首 2 时遇到了麻烦。
我想在运行时绑定一些依赖项而不是在编译时MainActivity
使用@Subcomponent.Builder
and@BindsInstance
我有一个 ApplicationComponent,它有一个 Builder,它的 @BindsInstance 看起来工作正常。我可以像下面这样使用
DaggerApplicationComponent
.builder()
.application(this)
.build()
.inject(this)
但一些麻烦来自 MainActivity ......
下面是代码片段
[应用组件]
@Singleton
@Component(modules = [ApplicationModule::class])
internal interface ApplicationComponent : AndroidInjector<MyApplication> {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: Application): Builder
fun build(): ApplicationComponent
}
}
[应用模块]
@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>
}
[主要组件]
@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
}
}
[主要活动]
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 不会自动生成它。我正在寻找很多网站来解决这个问题,但都失败了。有什么办法可以做到吗?
解决方案
我想,我已经找到了实现你想要的方法。很抱歉没有使用您的特定示例,但更容易粘贴我拥有的代码并且知道可以在我自己的 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>
}
主要应用
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)
}
}
运行时绑定活动
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)
}
}
至关重要的是要注意,您以这种方式生成的子组件不会被 dagger 神奇地存储在某个地方。如果您希望您的后期绑定实例可用于注入由您的@PerActivity
范围控制的其他类,您需要手动管理此子组件的生命周期。将它存储在某个地方(可能在您的自定义应用程序类中),然后您还必须将其引用设置为null
您的活动被销毁的时间,否则您将泄漏该活动。
推荐阅读
- java - Android Studio - 根据来自另一个活动的用户输入更新活动 TextView
- reactjs - 用 Jest 和 Enzyme 测试函数?
- excel - 使用 VBA 将图例条目标题设置为系列标题
- python - 根据一系列 pandas 过滤行
- google-maps - 如何在谷歌地图中调整标记与其坐标之间的差距?
- python - 从 pypi 安装我的新软件包时仅找到旧的 tensorflow 版本
- html - 如何使用纯 css 和 html 将三角形作为指针添加到 html 元素上
- html - Bootstrap - 导航栏无法正常工作
- php - DOMXpath 查询不返回任何内容,我找不到错误
- excel - Excel 公式汇总 12 个最近的单元格