Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lateinit property dispatchingAndroidInjector has not been initialized

I receive the above error "lateinit property dispatchingAndroidInjector has not been initialized " when I run my fragment in dagger2 .
The above error is triggered in my application class which is below

KotlinTemplateApplication.kt

     class KotlinTemplateApplication:Application(), HasActivityInjector  {
        lateinit var retroComponent:RetroComponent

@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>

companion object {
    @get:Synchronized
    lateinit var instance: KotlinTemplateApplication
     private set
}

override fun onCreate() {
    super.onCreate()
    instance = this
    retroComponent = DaggerRetroComponent.builder().retroModule(RetroModule(APIURL.BASE_URL)).build()
    //retroComponent.inject()

}



   fun fetchRetroComponent():RetroComponent{
   return retroComponent
   }

override fun activityInjector(): AndroidInjector<Activity> {
    return dispatchingAndroidInjector
}
   }


My Fragment class is as below :
I called dagger related code in onAttach() method of fragment :

RetroDIFragment:

      class RetroDIFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
lateinit var retroDIListViewModel: RetroDIListViewModel
lateinit var retroFitDIView: View
@Inject
lateinit var apiService: APIService

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    arguments?.let {
        param1 = it.getString(ARG_PARAM1)
        param2 = it.getString(ARG_PARAM2)
    }
    retroDIListViewModel = ViewModelProviders.of(activity!!).get(RetroDIListViewModel::class.java)
}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {
    // Inflate the layout for this fragment
    retroFitDIView =  inflater.inflate(R.layout.fragment_retro_di, container, false)

    return retroFitDIView
}

override fun onAttach(context: Context?) {
    super.onAttach(context)
    AndroidInjection.inject(activity)
    KotlinTemplateApplication.instance.fetchRetroComponent().inject(this@RetroDIFragment)

    retroDIListViewModel.fetchPostsFromWebSevice(apiService).observe(this,object : Observer<List<RetroModel>>{
        override fun onChanged(t: List<RetroModel>?) {
            for (i in t!!.indices)
                println(t[i].id)
        }

    })
}
companion object {
    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @param param2 Parameter 2.
     * @return A new instance of fragment RetroDIFragment.
     */
    // TODO: Rename and change types and number of parameters
    @JvmStatic
    fun newInstance(param1: String, param2: String) =
            RetroDIFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
}
    }


My component is as below :

RetroComponent :

 @Singleton
@Component(modules = arrayOf(RetroModule::class))
  interface RetroComponent {
    fun inject(retroDIFragment: RetroDIFragment)
   }


My Module is as below:

 @Module
   public class RetroModule(var urlPath:String) {


init{
    this.urlPath  = urlPath
}

@Singleton
@Provides
fun provideServiceAPI(retrofit: Retrofit):APIService{
    return retrofit.create(APIService::class.java)
}

@Singleton
@Provides
fun provideRetrofit():Retrofit{
    val retrofit = Retrofit.Builder()
            .baseUrl(urlPath)
            .addConverterFactory(ScalarsConverterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .client(providesOkHttpClientBuilder())
            .build()
    return  retrofit

}


private fun providesOkHttpClientBuilder(): OkHttpClient {

    val httpClient = OkHttpClient.Builder()
    return httpClient.readTimeout(1200, TimeUnit.SECONDS)
            .connectTimeout(1200, TimeUnit.SECONDS).build()

}
}


My Activity is as below

class RetroFitActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_retro_fit)
    supportFragmentManager.beginTransaction().replace(R.id.container_retro_di, RetroDIFragment()).commit()
}
   }


I included below code in my Gradle:

 implementation 'com.google.dagger:dagger:2.19'
implementation 'com.google.dagger:dagger-android:2.19'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.19'
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
kapt 'com.google.dagger:dagger-android-processor:2.19'
kapt 'com.google.dagger:dagger-compiler:2.19'
//moxy
compile 'com.arello-mobile:moxy-app-compat:1.1.1'
kapt 'com.arello-mobile:moxy-compiler:1.1.1'




Can anyone help me in fixing this issue.

like image 307
Android_programmer_office Avatar asked Nov 07 '18 18:11

Android_programmer_office


3 Answers

You need to change the AppComponent class inject method parameter:

@Singleton
@Component(modules = [
        AndroidInjectionModule::class,
        ActivityModule::class,
        AppModule::class
])
interface AppComponent {

        @Component.Builder
        interface Builder {
                @BindsInstance
                fun application(application: Application): Builder

                fun build(): AppComponent
        }

        fun inject(app: Application) // This is the piece of code you need to change
}
@Singleton
@Component(modules = [
        AndroidInjectionModule::class,
        ActivityModule::class,
        AppModule::class
])
interface AppComponent {

        @Component.Builder
        interface Builder {
                @BindsInstance
                fun application(application: Application): Builder

                fun build(): AppComponent
        }

        fun inject(app: YourCustomAppClass) // Change to your custom app class
}

Also, where you are doing this

  DaggerAppComponent
            .builder()
            .application(yourAppInstance)
            .build()
            .inject(yourAppInstance)

yourAppInstance needs to be of type YourCustomApp class instead of Application.

like image 111
nayan dhabarde Avatar answered Oct 23 '22 10:10

nayan dhabarde


The dispatchingAndroidInjector property has to be set eventually.

@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>

As it's annotated with @Inject, it seems like you wanted to inject it. But since KotlinTemplateApplication is an Application, you need to do this manually on your component:

retroComponent.inject(this@KotlinTemplateApplication)
like image 1
tynn Avatar answered Oct 23 '22 10:10

tynn


To use Dagger in a Fragment, you must add a DispatchingAndroidInjector <Fragment> in KotlinTemplateApplication

Edit KotlinTemplateApplication

class KotlinTemplateApplication : Application() , HasActivityInjector, HasSupportFragmentInjector {


    @Inject lateinit var activityInjector: DispatchingAndroidInjector<Activity>


    @Inject lateinit var fragmentInjector: DispatchingAndroidInjector<Fragment>



    override fun onCreate() {
        super.onCreate()

                ........

        DaggerAppComponent.builder().application(this).build().inject(this)

                .........
    }




    override fun activityInjector(): AndroidInjector<Activity> = activityInjector

    override fun supportFragmentInjector(): AndroidInjector<Fragment> = fragmentInjector

}

You can also create a special module for Fragments and then add it to interface RetroComponent

@Component(modules = arrayOf(RetroModule::class,FragmentModule::class)

@Module
abstract class FragmentModule {
    @ContributesAndroidInjector
    internal abstract fun contributeRetroDIFragment(): RetroDIFragment
}

Then in your Fragment RetroDIFragment

class RetroDIFragment : Fragment() {
    ......

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment
        retroFitDIView =  inflater.inflate(R.layout.fragment_retro_di, container, false)

        return retroFitDIView
    }

   .........

    /*---------------- Dagger Injection for Fragment -------------*/
    @Override
    override fun onAttach(context: Context?) {
        AndroidSupportInjection.inject(this)
        super.onAttach(context);
    }

}
like image 1
GRimmjow Avatar answered Oct 23 '22 09:10

GRimmjow