Reputation: 19848
I have an object that I'm trying to inject into 3 fragments as a singleton, using @Inject
annotations.
Component:
@Subcomponent(modules = [(MyModule::class)])
interface MyComponent {
fun inject(fragment: OneFragment)
fun inject(fragment: TwoFragment)
fun inject(fragment: ThreeFragment)
}
Module:
@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)
}
Fragments:
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
}
}
However, the presenters that are injected into the fragments are not the same unique instance. What am I doing wrong?
Upvotes: 2
Views: 1922
Reputation: 34532
It's not a @Singleton
because you did not tell Dagger that it is. You put the scope on the presenter which would be fine if you were using constructor injection, but you aren't.
@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)
So you have two options. Either you use constructor injection, or you use a @Provides
. You can't cherry pick and use a bit of each one.
Just remove the @Provides
annotated method in your module and slap an @Inject
on your constructor.
@Singleton // NOW we're doing constructor injection -> singleton!
class MyPresenterImpl @Inject constructor(override val view: MyView,
override val myService: MyService): MyPresenter
There is no need for a module declaring it now. If you want to bind it to an interface you can use the @Binds
annotation and continue using constructor injection...
@Binds // bind implementation to interface
abstract fun providePresenter(presenter : MyPresenterImpl) : MyPresenter
Since MyPresenterImpl
is a @Singleton
you don't have to declare MyPresenter
as a singleton also. It will always use the singleton under the hood. (I believe it might even have a slight bigger performance penalty doing scopes on both.)
@Provides method
Remove the scope from your class (where it does nothing but confuse), and put it on the @Provides
method instead. That's it.
@Singleton // singleton!
@Provides
fun providePresenter(view: MyView,
myService: MyService): MyPresenter =
MyPresenterImpl(view, myService)
Scope on the class for constructor injection, or scope on the @Provides
method if you're using that. Don't mix them up.
I'd personally recommend to go for constructor injetion whenever possible to do so as you don't have to manage/update the constructor calls yourself.
Upvotes: 4