I'm not able to build my app due to following error.
#Component.Builder is missing setters for required modules or components
I'm using
implementation "androidx.room:room-runtime:2.1.0"
kapt "androidx.room:room-compiler:2.1.0"
My apps RoomModul looks like this:
#Module
class RoomModule(application: Application) {
#Singleton
private var logDatabase : LogDatabase =
Room.databaseBuilder(application, LogDatabase::class.java, "log-db").build()
#Singleton
#Provides
fun providesLogDatabase() : LogDatabase {
return logDatabase
}
#Singleton
#Provides
fun providesLogDao() : LogDao {
return logDatabase.getLogDao()
}
#Singleton
#Provides
fun providesLogRepository(logDao: LogDao) : LogRepository {
return LogDataSource(logDao)
}
}
And my AppComponent looks like this:
#Singleton
#Component(
modules = [
AndroidInjectionModule::class,
AppModule::class,
MainActivityModule::class,
RoomModule::class
])
interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
fun inject(logApplication: LogApplication)
}
So my RoomModule needs the application to provide the room database. But I keep getting the error.
I thought that #BindsInstance should provide the application instance to my modules. I also tried to remove the constructor from my RoomModule with no success. Please let me know if I can provide more information.
Try to use this
#Module
class RoomModule()
{
#Singleton
#Provides
private var logDatabase(application: Application) : LogDatabase =
Room.databaseBuilder(application, LogDatabase::class.java, "log-db").build()
----
}
And Remove this line ---> fun inject(logApplication: LogApplication)
from AppComponent
Related
I'm learning dagger2 with a module architecture. And I think, something is not clear to me, for example
in module utilites i have di package
class UtilsComponent
#Component(modules = [UtilsModule::class])
interface UtilsComponent {
fun getResourceProvider() : IResourceProvider
fun getNetworkProvider(): INetworkProvider
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): UtilsComponent.Builder
fun build(): UtilsComponent
}
}
#Module
abstract class UtilsModule {
#Binds
abstract fun bindContext(application: Application): Context
#Module
companion object {
#Provides
#JvmStatic
fun bindResourceProvider(context: Context): IResourceProvider {
return ResourceProvider(context = context)
}
#Provides
#JvmStatic
fun bindNetworkProvider(context: Context): INetworkProvider {
return NetworkProvider(context = context)
}
}
}
then in app package in AppComponent i included all modules
#Component(
dependencies = [UtilsComponent::class],
modules = [
AndroidInjectionModule::class,
ActivityBindingModule::class,
MainModule::class // test module
]
)
#AppScope
interface AppComponent: AndroidInjector<App> {
// inject to ...
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): AppComponent.Builder
fun utilsComponent(utilsComponent: UtilsComponent): AppComponent.Builder
fun build(): AppComponent
}
}
In the app component, I have MainModule - this is my test module, so this module looks like this
#Module
class MainModule {
#Provides
fun getMainPresenter(networkProvider: NetworkProvider): MainPresenter {
return MainPresenter(networkProvider)
}
}
when I run the app, I have an error
[Dagger/MissingBinding] com.example.utilities.di.UtilsModule cannot be
provided without an #Provides-annotated method. public abstract
interface AppComponent extends
dagger.android.AndroidInjector<com.example.testmoduleapp.App> {
^
com.example.utilities.di.UtilsModule is injected at
com.example.testmoduleapp.di.modules.MainModule.getMainPresenter(utilsModule)
com.example.testmoduleapp.ui.activities.main.MainPresenter is injected at
com.example.testmoduleapp.ui.activities.main.MainActivity.mainPresenter
com.example.testmoduleapp.ui.activities.main.MainActivity is injected at
dagger.android.AndroidInjector.inject(T) [com.example.testmoduleapp.di.AppComponent →
com.example.testmoduleapp.di.modules.ActivityBindingModule_MainActivity.MainActivitySubcomponent]
I understand that the error is because I have not a module witch return NetworkProvider object, but I can't understand how I can get this object from UtilsModule
also in App
#Inject
lateinit var androidInjector : DispatchingAndroidInjector<Any>
override fun androidInjector(): AndroidInjector<Any> = androidInjector
companion object{
lateinit var appComponent: AppComponent
}
override fun onCreate() {
super.onCreate()
initializeDagger()
}
private fun initializeDagger() {
appComponent = DaggerAppComponent
.builder()
.application(this)
.utilsComponent(provideUtilsComponent())
.build()
}
private fun provideUtilsComponent(): UtilsComponent {
return DaggerUtilsComponent
.builder()
.application(this)
.build()
}
In Dependencies Graph You already provide INetworkProvider so when you need NetworkProvider it means Dagger can not be resolved. Change to this, don't forget to change constructor MainPresenter to INetworkProvider
#Provides
fun getMainPresenter(networkProvider: INetworkProvider): MainPresenter {
return MainPresenter(networkProvider)
}
but i cant understand how i can get this object from UtilsModule
For your question, in UtilComponent you already exposed getNetworkProvider() it means any Componenent dependencies to UtilsComponent can be get it.
I have a app with 3 different modules: app(main),api and repository
My app module depends on repository module, that depends on api module:
app -(depends)-> repository -(depends)-> api
I would like to use Dagger2 in all 3 modules to inject dependencies in each other without exposing theses dependencies to the modules that doesn't need to see it.
Basically the api module will provide service related classes to communicate with the API
The repository module will use the api classes to coordinate the call of the resources
The app module will use only the repository classes directly, without knowing anything of the api module
Here are how my dagger modules/components are structured:
ApiModule:
#Component(modules = [ApiModule::class])
interface ApiComponent {
#Component.Builder
interface Builder {
#BindsInstance
fun requestApiModule(apiModule: ApiModule): Builder
fun build(): ApiComponent
}
}
#Module
class ApiModule {
#Provides
#Reusable
fun provideApiClient(apiConfig: ApiConfig) = ApiClient(apiConfig)
#Provides
#Reusable
fun provideConsumerService(appConsumerService: AppConsumerService): ConsumerService = appConsumerService
#Provides
#Reusable
fun provideParkingService(appParkingService: AppParkingService): ParkingService = appParkingService
}
RepositoryModule:
#Component(
modules = [RepositoryModule::class],
dependencies = [ApiComponent::class]
)
interface RepositoryComponent {
#Component.Builder
interface Builder {
#BindsInstance
fun requestRepositoryModule(repositoryModule: RepositoryModule): Builder
fun apiComponent(apiComponent: ApiComponent): Builder
fun build(): RepositoryComponent
}
}
#Module
class RepositoryModule {
#Provides
#Reusable
fun provideLocalStorage(application: Application) = LocalStorage(application.applicationContext)
#Provides
#Reusable
fun provideLocalSession(application: Application) = LocalSession(application.applicationContext)
#Provides
#Reusable
fun provideApiConfig(apiRepositoryConfig: ApiRepositoryConfig): ApiConfig = apiRepositoryConfig
#Provides
#Reusable
fun provideConsumerRepository(appConsumerRepository: AppConsumerRepository): ConsumerRepository =
appConsumerRepository
#Provides
#Reusable
fun provideParkingRepository(appParkingRepository: AppParkingRepository): ParkingRepository = appParkingRepository
}
AppModule:
#Singleton
#Component(
modules = [ActivityModule::class, ViewModelModule::class, AndroidInjectionModule::class],
dependencies = [RepositoryComponent::class]
)
interface ApplicationComponent : AndroidInjector<CustomApplication> {
override fun inject(customApplication: CustomApplication)
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): Builder
fun repositoryComponent(repositoryComponent: RepositoryComponent): Builder
fun build(): ApplicationComponent
}
}
After trying to run the project I'm seeing the current errors in the build output
error: cannot access ApiComponent class file for com.spaces.api.module.ApiComponent not found Consult the following stack trace for details
error: [ComponentProcessor:MiscError] dagger.internal.codegen.ComponentProcessor was unable to process this interface because not all of its dependencies could be resolved. Check for compilation errors or a circular dependency with generated code.
I decided to learn dagger dependency injection framework. After some tutorials I try to implement dagger into my project. However I got this error
com\assigment\di\component\AppComponent.java:11: error: [Dagger/MissingBinding] java.util.Map<java.lang.Class<? extends android.app.Activity>,javax.inject.Provider<dagger.android.AndroidInjector.Factory<? extends android.app.Activity>>> cannot be provided without an #Provides-annotated method.
public abstract void inject(#org.jetbrains.annotations.NotNull()
^
java.util.Map<java.lang.Class<? extends android.app.Activity>,javax.inject.Provider<dagger.android.AndroidInjector.Factory<? extends android.app.Activity>>> is injected at
dagger.android.DispatchingAndroidInjector.<init>(injectorFactories)
dagger.android.DispatchingAndroidInjector<android.app.Activity> is injected at
assigment.com.assigment.App.activityInjector
assigment.com.assigment.App is injected at
assigment.com.assigment.di.component.AppComponent.inject(assigment.com.assigment.App)
I try to solve this for 2 days but with no luck. So here's how I set up my project
class App : Application(), HasActivityInjector {
#Inject
lateinit var activityInjector: DispatchingAndroidInjector<Activity>
lateinit var appComponent: AppComponent
override fun onCreate() {
super.onCreate()
appComponent = DaggerAppComponent
.builder()
.appModule(AppModule())
.build()
}
override fun activityInjector(): AndroidInjector<Activity> {
return activityInjector
}
}
Here's my app component
#Singleton
#Component(modules = [AppModule::class])
interface AppComponent : AndroidInjector<App> {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
override fun inject(app: App)
}
and here's my appModule class
AppModule
#Module
class AppModule {
private val url = "http://test.lt/v1/"
#Provides
#Singleton
fun provideApplication(app: Application): Context = app
}
So what I'm missing with this implementation?
Add AndroidInjectionModule.class and ActivityBuilder.class to your AppComponent
#Singleton
#Component(modules = [AndroidInjectionModule::class, AppModule::class, ActivityBuilder::class ])
interface AppComponent : AndroidInjector<App> {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
override fun inject(app: App)
}
You have two problems.
To get rid of the compiler error add AndroidInjectionModule::class to Component modules:
#Singleton
#Component(modules = [AndroidInjectionModule::class, AppModule::class])
interface AppComponent : AndroidInjector<App> {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
override fun inject(app: App)
}
With #Component.Builder annotated interface you define the builder interface with an annotated #BindsInstance method application() (note that there is not an appModule method declared in the Builder).
With such declaration you can build your component using application(this):
appComponent = DaggerAppComponent
.builder()
.application(this)
.build()
In this way this application instance is bound inside the component.
Just as a side note: Binding Instances are documented here, but personally I found the explanation quite hard to grasp for someone learning dagger, like me.
Detail answer with explanation
Component - >
Component is a graph. Component will provide injected instances by using modules.
#Component(
modules = [
AndroidInjectionModule::class, //We didn’t create this. It is an internal class in Dagger 2.10. Provides our activities and fragments with given module
ActivityModule::class,
]
)
#Singleton
interface AppComponent : AndroidInjector<App> {
#Component.Builder
interface Builder {
fun addContext(#BindsInstance context: Context): Builder
fun build(): AppComponent
}
}
We created ActivityModule module. This is a given module to dagger. We map all our activities here. And Dagger know our activities in compile time. In our app we have MainActivity. So we map it here.
#Module
abstract class ActivityModule {
#ContributesAndroidInjector
public abstract MainActivity bindMainActivity();
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest>
<application
android:name=".App"
App.kt
class App : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerAppComponent.builder().addContext(this).build()
}
}
And Make sure to extend your activity with DaggerAppCompatActivity that will auto inject before onCreate
I am using dagger 2.11
Module
#Module
class MyModule {
#Provides
fun provideString() : String = "yo"
#Provides #Named("injector")
fun provideInzectorString() : String = "named_injection"
#Singleton #Provides //The error goes away if I remove #Singleton
fun provideRepository() = Repository(Interceptor(),"")
}
Activity binding module
#Module
abstract class ActivityBindingModule {
#ContributesAndroidInjector(modules = [MyModule::class])
abstract fun suggestionActivity() : SuggestionsActivity
#ContributesAndroidInjector(modules = [MyModule::class])
abstract fun editSubscriptionActivity() : SubscribeActivity
}
AppComponent
#Singleton
#Component(modules = {
AndroidInjectionModule.class,
MyModule.class
})
interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(MyApplication application);
AppComponent build();
}
void inject(MyApplication app);
}
I get this error on compilation
SubscribeActivitySubcomponent (unscoped) may not reference scoped bindings:
#Singleton #Provides #org.jetbrains.annotations.NotNull
I have seen these solutions 1 and 2. Both ask you to annotate your appcomponent with #Singleton which I am already doing. What is wrong with my code?
The problem is MyModule's scope(Application or singleton) is bigger than an activity scope.
#ContributesAndroidInjector(modules = [MyModule::class])
abstract fun suggestionActivity() : SuggestionsActivity
Remove the two (modules = [MyModule::class])s or define activity specific modules.
You don't need MyModule here. It's redundant because it's already included in the AppComponent.
It is confusing that all web search results seem to use slightly different versions of Dagger or different approaches. I followed the example which claims that is the better "new way". (https://proandroiddev.com/exploring-the-new-dagger-android-module-9eb6075f1a46) The full sample source code is here (https://github.com/jshvarts/DaggerAndroidKotlinSampleApp).
Now, I want to know how a non-activity/fragment class could be provided with a Context. So, I added a simple class like this,
class Sample2 #Inject constructor (var app: Application)
{
fun print()
{
Log.d("sample2", app.packageName);
}
}
But even though the sample project had AppModule and AppComponent, the compilation failed, because app could not be provided.
I have searched the web and found this method (https://github.com/google/dagger/issues/832). I followed that code and modified the sample's AppModule and AppComponent like this,
#Module(includes = [AndroidInjectionModule::class])
abstract class AppModule {
#Binds
abstract fun application(app: App):Application;
#Singleton
#Provides
fun providesCommonHelloService() = CommonHelloService()
}
#Singleton
#Component(modules = [AndroidInjectionModule::class,
AppModule::class, ActivitiesModule::class])
interface AppComponent:AndroidInjector<App>
{
#Component.Builder
abstract class Builder:AndroidInjector.Builder<App>(){}
}
class App : Application(), HasActivityInjector {
#Inject
lateinit var activityInjector: DispatchingAndroidInjector<Activity>
override fun onCreate()
{
super.onCreate()
DaggerAppComponent.builder().create(this).inject(this)
}
override fun activityInjector(): AndroidInjector<Activity> = activityInjector
}
But the, I get the following compilation error.
AppModule.java:7: error: A #Module may not contain both non-static #Provides methods and abstract #Binds or #Multibinds declarations
public abstract class AppModule {
Again, as I have said in the beginning, the Dagger examples on the Internet are all slightly different, I do not know how to take two features from two examples.
It is better to separate #Binds and #Provides, you can create a component class:
#Singleton
#Component(
modules = [(AppModule::class)]
)
interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
fun application(app: Application): Builder
fun build(): AppComponent
}
}
then an AppModule class for all your #Provides
#Module
class AppModule() {
#Singleton
#Provides
fun providesCommonHelloService() = CommonHelloService()
}