Итак, я настроил проект с фрагментом SelfInjecting NavHost, основным компонентом приложения и компонентом DataListItems, который зависит от основного компонента приложения. Но у меня кошмар с удовлетворением зависимости от кинжала. Я перенес свою структуру зависимостей из более старого стиля реализации Dagger, который работал нормально, но теперь у меня есть проблемы.
class BaseArchCompApplication : Application(), HasAndroidInjector {
@Inject
lateinit var activityInjector: DispatchingAndroidInjector<Any>
override fun androidInjector() = activityInjector
override fun onCreate() {
super.onCreate()
// init application component.
DaggerBaseArchCompApplicationComponent.builder().application(this).build()
.inject(this)
}
**===========================Component and Modules with AppScope================**
@AppScope
@Singleton
@Component(modules = [AndroidInjectionModule::class, NavHostModule::class, BaseArchCompApplicationModule::class, DataModule::class, NetworkModule::class,
RestServiceModule::class, GsonModule::class, RxModule::class])
interface BaseArchCompApplicationComponent : AndroidInjector<Any> {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: BaseArchCompApplication): Builder
fun build(): BaseArchCompApplicationComponent
}
fun inject(baseArchCompApplication: BaseArchCompApplication){
val applicationComponent = DaggerBaseArchCompApplicationComponent.builder()
.application(baseArchCompApplication)
.build()
applicationComponent.inject(baseArchCompApplication)
}
fun context(): Context
fun picasso(): Picasso
fun environmentparameters(): EnvironmentParameters
fun preferencesmanager(): PreferencesManager
fun rxSchedulers(): AndroidRxSchedulers
fun dataService(): DataService
fun dataListItemsRepository(): DataListItemsRepository
}
==========================
@Module
class BaseArchCompApplicationModule {
@AppScope
@Provides
fun provideContext(baseArchCompApplication: BaseArchCompApplication) = baseArchCompApplication.applicationContext
}
================================
@Module
class DataModule {
@AppScope
@Provides
fun dataListItemsRepository(
appRemoteDataSource: DataListItemRemoteDataSource,
appLocalDataSource: DataListItemsLocalDataSource
): DataListItemsRepository {
return DefaultDataListItemsRepository(appRemoteDataSource, appLocalDataSource)
}
@AppScope
@Provides
fun createDataListItemRemoteDataSource(
appDatabase: BaseArchCompAppDatabase,
dataService: DataService
): DataListItemRemoteDataSource {
return DataListItemRemoteDataSource(appDatabase.dataListItemDao(), dataService)
}
@AppScope
@Provides
fun createDataListItemLocalDataSource(
appDatabase: BaseArchCompAppDatabase
): DataListItemsLocalDataSource {
return DataListItemsLocalDataSource(appDatabase.dataListItemDao())
}
@AppScope
@Provides
fun createDataBase(context: Context): BaseArchCompAppDatabase {
return Room.databaseBuilder(
context.applicationContext,
BaseArchCompAppDatabase::class.java, "DataListItems.db"
).build()
}
}
============================
@Module
class RestServiceModule {
@AppScope
@Provides
fun retrofit(
okHttpClient: OkHttpClient,
gson: Gson,
androidSchedulers: AndroidRxSchedulers,
environmentParameters: EnvironmentParameters
): Retrofit {
return Retrofit.Builder()
.baseUrl(environmentParameters.baseURL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(androidSchedulers.network()))
.addConverterFactory(GsonConverterFactory.create(gson))
.client(okHttpClient)
.build()
}
@AppScope
@Provides
fun dataService(retrofit: Retrofit): DataService {
return retrofit.create(DataService::class.java)
}
}
==========================================
@Module
class NavHostModule {
@AppScope
@Provides
fun injectingNavHostFragment(): InjectingNavHostFragment {
return InjectingNavHostFragment()
}
}
**=============Component and Modules with DataListItemsScope==========**
@DataListItemsScope
@Component(modules = arrayOf(AndroidInjectionModule::class, DataListItemsModule::class), dependencies = arrayOf(BaseArchCompApplicationComponent::class))
interface DataListItemsActivityComponent {
fun inject(dataListItemsActivity: DataListItemsActivity)
}
===============================
@Module
class DataListItemsModule {
@DataListItemsScope
@Provides
fun dataListItemsViewModel(dataListItemsRepository: DataListItemsRepository, dataService: DataService, preferencesManager: PreferencesManager, picasso: Picasso): DataListItemsViewModel {
return DataListItemsViewModel(dataListItemsRepository)
}
@DataListItemsScope
@Provides
fun dataListItemsFragment( picasso: Picasso, preferencesManager: PreferencesManager, viewModel: DataListItemsViewModel): DataListItemsFragment {
return DataListItemsFragment(viewModel)
}
@DataListItemsScope
@Provides
fun navHostFragment() : InjectingNavHostFragment{
return InjectingNavHostFragment()
}
}
=================================
class DataListItemsActivity : DaggerAppCompatActivity() {
private lateinit var drawerLayout: DrawerLayout
private lateinit var appBarConfiguration: AppBarConfiguration
@Inject
lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>
@Inject
lateinit var dataListItemsViewModel: DataListItemsViewModel
@Inject
lateinit var dataListItemsFragment: DataListItemsFragment
@Inject
lateinit var dataListItemsRepository: DataListItemsRepository
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.data_items_act)
setupNavigationDrawer()
setSupportActionBar(findViewById(R.id.toolbar))
DaggerDataListItemsActivityComponent.builder()
.dataListItemsModule(DataListItemsModule())
.build().inject(this)
val navController: NavController = findNavController(R.id.nav_host_fragment)
appBarConfiguration =
AppBarConfiguration.Builder(R.id.dataListItems_fragment_dest)
.setDrawerLayout(drawerLayout)
.build()
setupActionBarWithNavController(navController, appBarConfiguration)
findViewById<NavigationView>(R.id.nav_view)
.setupWithNavController(navController)
}
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.nav_host_fragment).navigateUp(appBarConfiguration)
|| super.onSupportNavigateUp()
}
private fun setupNavigationDrawer() {
drawerLayout = (findViewById<DrawerLayout>(R.id.drawer_layout))
.apply {
setStatusBarBackground(R.color.colorPrimaryDark)
}
}
}
Когда я компилирую, я получаю
**java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mycompany.base_arch_comp_app.mock/com.mycompany.base_arch_comp_app.datalistitem.DataListItemsActivity}: java.lang.IllegalArgumentException: No injector factory bound for Class<com.mycompany.base_arch_comp_app.datalistitem.DataListItemsActivity>**
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
**Caused by: java.lang.IllegalArgumentException: No injector factory bound for Class<com.mycompany.base_arch_comp_app.datalistitem.DataListItemsActivity>**
at dagger.android.DispatchingAndroidInjector.inject(DispatchingAndroidInjector.java:136)
at dagger.android.AndroidInjection.inject(AndroidInjection.java:181)
at dagger.android.AndroidInjection.inject(AndroidInjection.java:55)
at dagger.android.support.DaggerAppCompatActivity.onCreate(DaggerAppCompatActivity.java:41)
at com.mycompany.base_arch_comp_app.datalistitem.DataListItemsActivity.onCreate(DataListItemsActivity.kt:60)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I am generally having a problem as most of the examples if not all seems to deal with the basic case of a simple Main Activity and a Detailed activity, without any dependencies between the components, so they get away with something like
@Subcomponent (
modules = [
DetailFragmentModule::class
]
)
interface DetailActivityComponent: AndroidInjector<DetailActivity> {
@Subcomponent.Factory
interface Factory : AndroidInjector.Factory<DetailActivity>
}
@Module(subcomponents = [
DetailActivityComponent::class
])
abstract class DetailActivityModule {
@Binds
@IntoMap
@ClassKey(DetailActivity::class)
internal abstract fun bindDetailActivityFactory(factory: DetailActivityComponent.Factory): AndroidInjector.Factory<*>
}
Что звучит хорошо довы вводите зависимости от основного компонента приложения и все @Provides от самого компонента Detail