Field not being injected with Dagger - android

In the following code, the field serviceUtil is not being injected by Dagger:
AppController.kt
class App : Application() {
#Inject
lateinit var serviceUtil: ServiceUtil
init {
DaggerAppComponent
.builder()
.build()
.inject(this)
}
override fun onCreate() {
super.onCreate()
context = this
}
fun startService() {
serviceUtil.startService()
}
companion object {
lateinit var context: App
}
}
AppComponent.kt
#Singleton
#Component(modules = [(ServiceUtilModule::class)])
interface AppComponent {
fun inject(app: Application)
}
ServiceUtilModule.kt
#Module
class ServiceUtilModule {
#Provides
fun provideServiceUtil() : ServiceUtil {
return ServiceUtil()
}
}
From my main activity I call:
App.context.startService()

You mistyped here
#Singleton
#Component(modules = [(ServiceUtilModule::class)])
interface AppComponent {
fun inject(app: Application)
}
You should pass you App class as argument, not the basic one.
#Singleton
#Component(modules = [(ServiceUtilModule::class)])
interface AppComponent {
fun inject(app: App)
}

Related

Android dagger2 , some things not clear

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.

Trouble with Dagger 2

Hello i am using dagger 2 in my project with this configuration.
This is my SellerHubApplication.kt
class SellerHubApplication : Application(), HasAndroidInjector {
#Inject
lateinit var activityDispatchingAndroidInjector: AndroidInjector<Any>
override fun androidInjector(): AndroidInjector<Any> = activityDispatchingAndroidInjector
override fun onCreate() {
super.onCreate()
DaggerAppComponent.builder()
.application(this)
.build()
.inject(this)
Fresco.initialize(applicationContext)
}
}
and this is my AppComponent.kt
#Singleton
#Component(modules = [AndroidInjectionModule::class, ActivityBuilder::class, AppModule::class])
interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
fun application(app: Application): Builder
fun build(): AppComponent
}
fun inject(app: SellerHubApplication)
}
After i run the application, i get this error "error: [Dagger/MissingBinding] dagger.android.AndroidInjector cannot be provided without an #Provides-annotated method."
if i change the "fun inject(app: SellerHubApplication)" to "fun inject(app: Application)", application runs but it says "activityDispatchingAndroidInjector has not been initialized". Please help me with this.
Try to do it as such:
AppComponent:
#Singleton
#Component(modules = [AndroidInjectionModule::class, ActivityBuilder::class, AppModule::class, FragmentBuilder::class,])
interface AppComponent : AndroidInjector< SellerHubApplication > {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: SellerHubApplication): Builder
fun applicationModule(applicationModule: AppModule): Builder
fun build(): AppComponent
}
}
Application:
class SellerHubApplication : Application(), HasActivityInjector, HasSupportFragmentInjector {
#Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
#Inject
lateinit var fragmentInjector: DispatchingAndroidInjector<Fragment>
companion object {
lateinit var applicationComponent: AppComponent
private set
}
override fun onCreate() {
super.onCreate()
init()
}
override fun activityInjector(): AndroidInjector<Activity> {
return dispatchingAndroidInjector
}
override fun supportFragmentInjector(): AndroidInjector<Fragment> {
return fragmentInjector
}
private fun init() {
initDagger()
}
private fun initDagger() {
applicationComponent = DaggerAppComponent
.builder()
.application(this)
.applicationModule(AppModule(this))
.build()
applicationComponent.inject(this)
}
}
AppModule:
#Module
class AppModule(private val application: SellerHubApplication) {
#Provides
#Singleton
fun provideApplication(): Application {
return application
}
}

Dagger2 + Kotlin: lateinit property appComponent has not been initialized

I'm using Dagger2 to inject class dependent like bellow.
This is a component for Dagger2, AppComponent.kt:
#Component(modules = [ContextModule::class, SuggestModule::class, RetrofitModule::class,
TranslateModule::class, DatabaseModule::class, ViewModelModule::class, FragmentModule::class])
interface AppComponent {
#Singleton
fun inject(fragment: TranslateFragment)
#Singleton
fun inject(fragment: FavouriteFragment)
#Singleton fun inject(fragment: TensesFragment)
#Singleton
fun inject(activity: TensesActivity)
#Singleton
fun inject(activity: MainActivity)
#Singleton
fun inject(translateViewModel: TranslateViewModel)
#Singleton
fun inject(favouriteViewModel: FavouriteViewModel)
#Singleton
fun inject(translateProvider: TranslateProvider)
}
This is App class extended Application class, where i built my component , App.kt
class App : Application() {
companion object{
lateinit var appComponent: AppComponent
}
override fun onCreate() {
super.onCreate()
appComponent = DaggerAppComponent.builder()
.contextModule(ContextModule(this))
.suggestModule(SuggestModule(this))
.retrofitModule(RetrofitModule())
.translateModule(TranslateModule(TranslateProvider()))
.databaseModule(DatabaseModule(DatabaseManager(this)))
.viewModelModule(ViewModelModule())
.fragmentModule(FragmentModule())
.build()
}
}
First, i injected TranslateFragment into MainActivity, MainActivity.kt
class MainActivity : AppCompatActivity {
constructor(){
App.appComponent.inject(this)
}
#Inject
lateinit var translateFragment: TranslateFragment
}
Second, i injected TranslateViewModel into TranslateFragment, TranslateFragment.kt
class TranslateFragment : Fragment {
#Inject
constructor() {
App.appComponent.inject(this)
}
#Inject
lateinit var translateViewModel: TranslateViewModel
}
Third, i injected TranslateProvider into TranslateViewModel, TranslateViewModel.kt
class TranslateViewModel : BaseObservable {
#Inject
constructor() {
App.appComponent.inject(this)
}
#Inject
lateinit var translateProvider: TranslateProvider
}
End, i injected RetrofitProvider into TranslateProvider, TranslateProvider.kt
class TranslateProvider {
#Inject
constructor() {
App.appComponent.inject(this)
}
#Inject
lateinit var retrofitProvider: RetrofitProvider
}
But i received a error at TranslateProvider.kt:
kotlin.UninitializedPropertyAccessException: lateinit property
appComponent has not been initialized
I'm not understand, please help me.
Thanks!
I created a instance of TranslateProvider in: .translateModule(TranslateModule(TranslateProvider()))
When constructor of TranslateProvider called appComponent, but appComponent was not initialized that time.
Just move it go to out of TranslateModule constructor look like:
Before:
#Module
class TranslateModule(private val translateProvider: TranslateProvider) {
#Provides
fun getTranslateProvider(): TranslateProvider {
return translateProvider
}
}
After:
#Module
class TranslateModule {
#Provides
fun getTranslateProvider(): TranslateProvider {
return TranslateProvider()
}
}

Injecting dependencies in a Android ViewModel?

Hi i have a ViewModel that has two var's that get injected using Dagger 2.11.
However it never gets injected in my viewModel whilst everywhere else in my app, these same dependecy Vars get initialised and injected perfectly
Below is my viewModel
class MyViewModel : AndroidViewModel, MyViewModelContract {
private lateinit var pointsBalance: MutableLiveData<PointsBalance>
#Inject
lateinit var accountDelegator: AccountDelegatorContract
#Inject
constructor(application: Application) : super(application)
init {
DaggerApplicationComponent.builder().application(getApplication() as MyApplication).build().inject(this)
}
override fun getPointsBalance(): LiveData<PointsBalance> {
if (!this::pointsBalance.isInitialized) {
//get balance from network api etc
}
return pointsBalance
}
accountDelegator complains that it is not initialised
Below is how i bind this viewModel inside MyModule.class
#Provides
#JvmStatic
#Singleton
fun providesViewModel(viewModel: MyViewModel): MyViewModelContract = viewModel
my custom application
class MyApplication : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
val applicationComponent = DaggerApplicationComponent.builder()
.application(this)
.build()
applicationComponent.inject(this)
return applicationComponent
}
}
my applicationComponent
#Singleton
#Component(modules = arrayOf(MyModule::class,
))
interface ApplicationComponent : AndroidInjector<DaggerApplication> {
fun inject(mApplication: MyApplication)
override fun inject(instance: DaggerApplication)
#Component.Builder
interface Builder {
#BindsInstance
fun application(applicaton: MyApplication): Builder
fun build(): ApplicationComponent
}
}
How i use this viewmodel in a activity/fragment
viewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)
I believe issue is that you're not calling inject. You'd need for a start to add following to ApplicationComponent
void inject(MyViewModel viewModel);
What I'm doing here then fwiw is inheriting from AndroidViewModel (which gives access to application instance) then calling following in ViewModel class (you'd need to substitute DaggerProvider.getComponent with however you're accessing component in your code)
init {
DaggerProvider.getComponent(application).inject(this)
}

Cannot be Provided Without an #Provides-annotated Method

There have been many other similar questions, but none of the answers have been applicable to my code. I cannot figure out what I have done wrong.
First I have a NetworkModule that is used as a module for the ApplicationComponent:
#Module
open class NetworkModule {
companion object {
private val BASE = "http://www.example.com/"
}
#Provides #ApplicationScope
fun provideClient(): OkHttpClient = OkHttpClient()
#Provides #ApplicationScope
fun provideMoshi(): Moshi {
return Moshi.Builder().add(InstantAdapter).add(UriAdapter).build()
}
#Provides #ApplicationScope
fun provideRetrofit(client: OkHttpClient, moshi: Moshi): Retrofit {
return Retrofit.Builder().client(client).baseUrl(BASE)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
}
#Provides #ApplicationScope
fun provideArticleService(retrofit: Retrofit): ArticleService {
return retrofit.create(ArticleService::class.java)
}
}
#ApplicationScope #Component(modules = arrayOf(ContextModule::class, RealmModule::class, NetworkModule::class))
interface ApplicationComponent {}
Then the ApplicationComponent is built in my Application class:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
plantLog()
drawDagger()
}
private fun drawDagger() {
Injector.initializeApplicationComponent(this)
}
// ...
}
object Injector {
lateinit var applicationComponent: ApplicationComponent
private set
fun initializeApplicationComponent(context: Context) {
applicationComponent = DaggerApplicationComponent.builder()
.contextModule(ContextModule(context))
.networkModule(NetworkModule())
.realmModule(RealmModule())
.build()
}
// ...
}
Then I have an ActivityModule that is used in the ActivityComponent (which has ApplicationComponent as a dependency):
#Module
open class ActivityModule(private val activity: AppCompatActivity) {
#Provides #ActivityScope #ActivityContext
fun provideContext(): Context = activity
#Provides #ActivityScope
fun provideFragmentManager(): FragmentManager = activity.supportFragmentManager
}
#ActivityScope #Component(dependencies = arrayOf(ApplicationComponent::class), modules = arrayOf(ActivityModule::class))
interface ActivityComponent {
fun inject(activity: MainActivity)
}
Finally, I create a new ActivityComponent in the MainActivity and #Inject the ArticleService:
class MainActivity : AppCompatActivity() {
#Inject lateinit var service: ArticleService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
DaggerActivityComponent.builder()
.applicationComponent(Injector.applicationComponent)
.activityModule(ActivityModule(this))
.build().inject(this)
service.getNewsArticles()
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.newThread())
.subscribe(
{ response -> onNext(response) },
{ error -> onError(error) })
}
// ...
}
But when I try to build I get the following error, even though I believe the provideArticleService() function in NetworkModule is annotated correctly:
ArticleService cannot be provided without an #Provides- or
#Produces-annotated method.
You're missing the provision methods to inherit to your Activity scoped component. Either use subcomponents instead of component dependency, or define the provision methods in your application component.
#ApplicationScope #Component(modules = arrayOf(ContextModule::class, RealmModule::class, NetworkModule::class))
interface ApplicationComponent {
ArticleService articleService();
}

Categories

Resources