I have two activities that uses ViewModelProvider, which must be injectied with Dagger.
To provide injection in an activity, I must call appComponent.inject() method. I can make it to MainActivity. But I can't use it in another activities (obviously because appComponent.inject() takes MainActivity instance as an argument).
So, the question is: What shall I do with AppComponent (or with smth. else), to be able to get instance of AppComponent from different activities (not only from MainActivity).
P.S. Possibly, it's something about Dagger Scopes, but I can't figure out what exactly to do.
AppComponent.kt
...
@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
fun inject(mainActivity: MainActivity)
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: Application): Builder
fun create(): AppComponent
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
@Inject
lateinit var viewModelProvider: Provider<MainActivityViewModel.Factory>
private val viewModel: MainActivityViewModel by viewModels { viewModelProvider.get() }
private lateinit var recyclerView : RecyclerView
private val adapter by lazy(LazyThreadSafetyMode.NONE) {
RecyclerViewAdapter(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
appComponent.inject(this)
setContentView(R.layout.activity_main)
setupViewModel()
setupUI()
}
private fun setupViewModel(){
viewModelProvider.get()
viewModel.setQuery("Apple")
}
private fun setupUI(){
recyclerView = findViewById(R.id.recyclerView)
GridLayoutManager(this,3, RecyclerView.VERTICAL,false
).apply {
recyclerView.layoutManager = this
}
recyclerView.adapter = adapter
addRepeatingJob(Lifecycle.State.STARTED) {
viewModel.images.collectLatest(adapter::submitData)
}
}
}
ViewPager.kt
class ViewPagerActivity : AppCompatActivity() {
@Inject
lateinit var viewModelProvider: Provider<MainActivityViewModel.Factory>
private val viewModel: MainActivityViewModel by viewModels { viewModelProvider.get() }
private lateinit var viewPager: ViewPager2
private val adapter by lazy(LazyThreadSafetyMode.NONE) {
ViewPagerAdapter(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_view_pager)
Log.d("dbg", intent.getIntExtra("ARG", 0).toString())
setupViewModel()
setupUI();
}
private fun setupUI()
{
viewPager = findViewById(R.id.viewPager)
viewPager.adapter = adapter
addRepeatingJob(Lifecycle.State.STARTED) {
viewModel.images.collectLatest(adapter::submitData)
}
}
private fun setupViewModel()
{
viewModelProvider.get()
}
}
Thanks.
AppComponent's Builder takes an Application. You haven't specified how you create or store AppComponent, but presumably it's either in the Application instance or in a static field to preserve its @Singleton
property.
In that case, you can create a second inject
method, named similarly or differently, which takes your SecondActivity
:
fun inject(mainActivity: MainActivity)
fun inject(secondActivity: SecondActivity)
Each of those is a members injection method: Dagger will inspect the object at compile time, figure out what is labeled with an @Inject
annotation, and call the methods and populate the fields when you call inject
. You can use the same component for this or use a different one.
Eventually, if you want to be able to inject the same instance within an Activity but different instances between different Activities, you may look into a second component (possibly a subcomponent) with a scope annotation like @ActivityScope
that you would write. You could also look into adopting Hilt, which would manage some of these scopes for you.