Search code examples
androidkotlindependency-injectionretrofit2dagger-2

lateinit property apiComponent has not been initialized in Dagger 2


I'm trying to implement Dragger 2 in recyclerview but I'm getting following error when running the app:

kotlin.UninitializedPropertyAccessException: lateinit property apiComponent has not been initialized
        at com.kabelash.squarerepos.MyRetroApplication$Companion.getApiComponent(MyRetroApplication.kt:18)
        at com.kabelash.squarerepos.network.viewmodel.RetroViewModelFactory.create(RetroViewModelFactory.kt:21)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:130)
        at com.kabelash.squarerepos.network.view.RetroFragment.initViewModel(RetroFragment.kt:43)
        at com.kabelash.squarerepos.network.view.RetroFragment.onCreate(RetroFragment.kt:29)

APIComponent.kt

@Singleton
@Component(modules = [AppModule::class, APIModule::class])
interface APIComponent {
    fun inject(retrofitRepository: RetrofitRepository)
    fun inject(retroViewModel: RetroViewModel)
    fun inject(retroFragment: RetroFragment)
    fun inject(retroViewModelFactory: RetroViewModelFactory)
}

NetworkActivity.kt class NetworkActivity: AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.network_layout)
    replaceFragment()
}


fun replaceFragment(){
   supportFragmentManager
       .beginTransaction()
       .replace(R.id.container_retro_room, RetroFragment())
       .commit()
}

}

RetroFragment.kt

class RetroFragment: Fragment() {

    lateinit var retroViewModel: RetroViewModel
    var fragmentView:View?=null
    private  var listAdapter: PostListAdapter?=null
    private var  postListLayoutBinding:PostListLayoutBinding?=null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initViewModel()
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        postListLayoutBinding = DataBindingUtil.inflate(inflater, R.layout.post_list_layout,container,false)
        fragmentView = postListLayoutBinding?.root
        initAdapter()
        setAdapter()
        fetchRetroInfo()
        return  fragmentView
    }

    fun  initViewModel(){
        var retroViewModelFactory = RetroViewModelFactory()
        retroViewModel = ViewModelProviders.of(this,retroViewModelFactory).get(RetroViewModel::class.java)
    }

    fun fetchRetroInfo(){
        retroViewModel.postInfoLiveData?.observe(this,object:Observer<List<PostInfo>>{
            override fun onChanged(t: List<PostInfo>?) {
                t?.apply {
                    listAdapter?.setAdapterList(t)
                }


            }
        })
    }

    private fun setAdapter(){
        fragmentView?.post_list?.apply {
            layoutManager = LinearLayoutManager(activity)
            addItemDecoration(DividerItemDecoration(activity, DividerItemDecoration.VERTICAL))
            adapter = listAdapter
        }

    }

   private fun initAdapter(){
       listAdapter = PostListAdapter(this@RetroFragment.requireActivity())
   }

}

RetroViewModelFactory.kt class RetroViewModelFactory : ViewModelProvider.Factory { lateinit var apiComponent: APIComponent @Inject lateinit var retrofitRepository: RetrofitRepository

override fun <T : ViewModel?> create(modelClass: Class<T>): T {
 //   initDaggerComponent()
   var apiComponent : APIComponent =  MyRetroApplication.apiComponent
    apiComponent.inject(this)
    if (modelClass.isAssignableFrom(RetroViewModel::class.java)) {
        return RetroViewModel(retrofitRepository) as T
    }
    throw IllegalArgumentException("Unknown ViewModel class")
}

fun initDaggerComponent(){
    apiComponent =   DaggerAPIComponent
        .builder()
        .aPIModule(APIModule(APIURL.BASE_URL))
        .build()
    apiComponent.inject(this)
}

}

Can someone help to fix this issue? I couldn't figure it out.


Solution

  • As the exception message says, you have a property called apiComponent marked with lateinit in your MyRetroApplication class, which has not been initialized. A lateinit property causes this exception if you attempt to read its value (such as here, within the factory) before setting it. You should create an instance of APIComponent in the MyRetroApplication class when your application starts, and assign it to that property.