Android Dagger2单例实际上不是单例问题
我有一个对象,我正试图使用Android Dagger2单例实际上不是单例问题,android,dependency-injection,dagger-2,Android,Dependency Injection,Dagger 2,我有一个对象,我正试图使用@inject注释将它作为一个单体注入到3个片段中 组成部分: @Subcomponent(modules = [(MyModule::class)]) interface MyComponent { fun inject(fragment: OneFragment) fun inject(fragment: TwoFragment) fun inject(fragment: ThreeFragment) } 模块: @Module class MyM
@inject
注释将它作为一个单体注入到3个片段中
组成部分:
@Subcomponent(modules = [(MyModule::class)])
interface MyComponent {
fun inject(fragment: OneFragment)
fun inject(fragment: TwoFragment)
fun inject(fragment: ThreeFragment)
}
模块:
@Module
class MyModule(val view: MyView) {
@Provides
fun provideView(): MyView = view
@Provides
fun providePresenter(view: MyView,
myService: MyService): MyPresenter =
MyPresenterImpl(view, myService)
}
MyPresenterImpl:
@Singleton
class MyPresenterImpl(override val view: MyView,
override val myService: MyService): MyPresenter {
private val TAG = javaClass.simpleName
// other code (irrelevant)
}
片段:
class OneFragment : Fragment() {
@Inject
lateinit var myPresenter: MyPresenter
override fun onCreateView(inflater: LayoutInflater, viewGroup: ViewGroup?,
bundle: Bundle?): View? {
activity?.mainApplication?.appComponent?.plus(
MyModule(activity as MyActivity))?.inject(this)
val view = inflater.inflate(R.layout.fragment_one, viewGroup, false)
//other meaningless code
return view
}
}
但是,注入片段的演示者不是同一个唯一实例。我做错了什么?它不是一个
@Singleton
,因为你没有告诉Dagger它是。您将作用域放在了presenter上,如果您使用的是构造函数注入,这将很好,但是您没有
@Singleton // does nothing. you're not doing constructor injection.
class MyPresenterImpl(override val view: MyView,
override val myService: MyService): MyPresenter
// ...and in your module...
@Provides // where's the scope? it's unscoped.
fun providePresenter(view: MyView,
myService: MyService): MyPresenter =
MyPresenterImpl(view, myService)
所以你有两个选择。要么使用构造函数注入,要么使用@Provides
。你不能随便挑选和使用每一个
1.构造函数注入
只需删除模块中带有注释的@Provides
方法,并在构造函数上插入@Inject
@Singleton // NOW we're doing constructor injection -> singleton!
class MyPresenterImpl @Inject constructor(override val view: MyView,
override val myService: MyService): MyPresenter
现在不需要模块来声明它。如果要将其绑定到接口,可以使用@Binds
注释并继续使用构造函数注入
@Binds // bind implementation to interface
abstract fun providePresenter(presenter : MyPresenterImpl) : MyPresenter
由于MyPresenterImpl
是一个@Singleton
,因此您不必将MyPresenter
也声明为一个Singleton。它将始终使用引擎盖下的singleton。(我相信在这两个方面都使用scopes可能会带来更大的性能损失。)
2. <代码>@提供了方法
将作用域从类中移除(在类中它只会混淆),并将其放在@Provides
方法中。就这样
@Singleton // singleton!
@Provides
fun providePresenter(view: MyView,
myService: MyService): MyPresenter =
MyPresenterImpl(view, myService)
类上的作用域用于构造函数注入,或者
@上的作用域提供了方法(如果您正在使用该方法)。不要把它们混在一起
我个人建议尽可能使用constructor injetion,因为您不必自己管理/更新构造函数调用。您可能不是从超级作用域组件继承presenter,而是为每个子组件创建一个新的presenter。这不是使用@Singleton的地方。@Singleton应该标记provider方法,告诉Dagger返回的值是Singleton。可以在Presenter类上使用@Singleton
。事实上,square建议将范围注释作为“实现细节”放在实现中的位置。请参阅的“偏好@injectover@Provides”部分。问题是您还应该使用@Inject
注释该构造函数。把所有的东西都放在一个地方。singleton不是仅仅是一个范围注释,并且仅仅意味着组件范围中只有一个对象吗?由于每个片段都在创建一个新组件,因此在出现@提供的情况下将创建一个新的presenter对象,但是,在堆栈溢出的每个其他答案中,我如何区分@Singleton
和'Singleton',并指出它们之间的区别将导致比它所能防止的更多的混淆<代码>@Singleton
在dagger的上下文中,总是意味着每个@Singleton
作用域组件都有一个实例,但通常只有一个,这就是为什么它在大多数情况下最终会成为一个实际的Singleton。这种解决方案是错误的。将注入放在构造函数上并不意味着它将自动注入到使用lateinit var myPresenter:myPresenter的类中-在成员变量上使用lateinit绝对需要使用组件,而组件又需要模块。因此,与您声称不需要任何模块相反,它是必需的。@AndroidDev拥有一个@Inject
注释构造函数,使Dagger能够提供/注入依赖项,就像@提供带注释的方法、@Binds
方法或@BindsInstance
生成器方法一样。我并没有说Dagger会自动执行任何操作,lateinit
是一个Kotlin构造,与Dagger本身无关,我想你是说场注入?当然,您需要一个组件,但组件不需要模块。这里不是讨论的地方,所以如果你有具体问题,请提出新问题并提供更多细节。