I am trying to replicate this this Singleton using Dagger 2.
I would like to have a BehaviorSubject in which I call onNext()
to in a service and subscribe()
to in a ViewModel.
Here is my Singleton object:
object MyMessageBus {
val pusher = BehaviorSubject.create<String>()
}
In my Service I can do this:
private val pusherObservable = MyMessageBus.pusher
override fun onCreate() {
super.onCreate()
println("service myObservable = ${pusherObservable.hashCode()}")
}
and then in my ViewModel I can do this:
private val pusherObservable = MyMessageBus.pusher
init {
println("viewModel myObservable = ${pusherObservable.hashCode()}")
}
When I run with this I get the same observable in both the Service and the ViewModel.
viewModel myObservable = 218654319
service myObservable = 218654319
and so I can call onNext in the Service and observe the change in the ViewModel.
As I said above I am trying to replicate this using Dagger, but I cant seem to get the same instance in both the Service and the ViewModel. I think the problem is that I just have two different graphs, but I cant figure out how to join them - even after reading the docs and knowing about Subcomponents.
Besides that, this seems like a huge amount of code to do something so simple.
So my question is how do I do the equivalent using Dagger with the minimum amount of code?
Here is what I have tried so far:
Here is the class I would like to inject into the Service and ViewModel.
Note: I originally thought just annotating the class and constructor would work, but have also tried with a module (hence the comments)
//@Singleton
class MessageBus {
val pusher: BehaviorSubject<String>
// @Inject
constructor() {
pusher = BehaviorSubject.create<String>()
}
}
Here is the module for providing the Service injections
@Singleton
@Module()
abstract class AndroidModule {
@ContributesAndroidInjector
abstract fun contributesPusherService(): PusherService
}
Here is the module that provides the MessageBus (Note I also tried just using commented out annoations above.
@Module
class PervasiveModule {
@Provides @Singleton fun provideMessageBus() = MessageBus()
}
Next is the App component
@Singleton
@Component(modules = arrayOf(AndroidInjectionModule::class, AndroidModule::class, PervasiveModule::class))
interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun application(myApp: MyApp): Builder
fun build(): AppComponent
}
fun inject(myApp: MyApp): MyApp
}
finally the component for the ViewModel.
@Component(modules = arrayOf(PervasiveModule::class))
@Singleton
interface MainViewModelComponent {
@Component.Builder
interface Builder {
fun build(): MainViewModelComponent
}
fun inject(mainViewModel: MainViewModel)
}
In the service I have:
@Inject lateinit var messageBus: MessageBus
override fun onCreate() {
AndroidInjection.inject(this)
super.onCreate()
setupPusher()
println("service created")
println("service messageBus = ${messageBus.hashCode()}")
}
In the ViewModel I have:
@Inject lateinit var messageBus: MessageBus
init {
DaggerMainViewModelComponent.create().inject(this)
println("view model messageBus = ${messageBus.hashCode()}")
}
When I run this, everything is injected, but I end up with two instances of MessageBus rather than one.
view model messageBus = 252114254
service messageBus = 91479273
As I said above I think the issue is that MainViewModelComponent
and the AppComponent
are actually two different graphs. Is this the case? If so how do I join them. If not can someone explain what's going on and how to get this to work.