Can't inject same instance into a Service and

2019-06-04 08:53发布

问题:

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.