UninitializedPropertyAccessException: lateinit property has not been initialized
Asked Answered
C

5

38

I have a class which i inject into a ViewModel + ViewModel factory, when initialise the view model in the onCreate method in activity, its says the value being passed through is not initialised.

Below is my code

I am quite new to Kotlin so have tried debugging but am stuck on this issue.

Here is MainActivity code:

class MainActivity: AppCompatActivity(), RepoSelectedListener {


    @Inject
    lateinit var viewModel: MainActivityListViewModel

    lateinit var lifecycleOwner: LifecycleOwner
    lateinit var repoSelectedListener: RepoSelectedListener

    @Inject
    lateinit var repository: RepoRepository


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        viewModel = ViewModelProviders.of(this, ViewModelFactory(repository)).get(MainActivityListViewModel::class.java)

        repoRecyclerView.apply {
            layoutManager = LinearLayoutManager(context)
            adapter = RepoListAdapter(viewModel, lifecycleOwner, repoSelectedListener)
        }


**My ViewModel:**



   class MainActivityListViewModel @Inject constructor(val 
    repoRepository: RepoRepository): BaseViewModel() {

    //private lateinit var repoRepository: RepoRepository
    private var disposable: CompositeDisposable? = null

    private val repos = MutableLiveData<List<Repo>>()
    private val repoLoadError = MutableLiveData<Boolean>()
    private val loading = MutableLiveData<Boolean>()


     init {
        disposable = CompositeDisposable()
        fetchRepos()
      }

     fun getRepos(): LiveData<List<Repo>> {
        return repos
     }
    }

my ViewModelFactory:

   class ViewModelFactory @Inject constructor(private val 
   repoRepository: RepoRepository): ViewModelProvider.Factory{


    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if 
   (modelClass.isAssignableFrom(MainActivityListViewModel::class.java)) 
   {
            @Suppress("UNCHECKED_CAST")
            return MainActivityListViewModel(this.repoRepository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")

    }


   }

my Class Repo:

  class RepoRepository @Inject constructor(private val githubRepos: 
    GithubRepos){


    private lateinit var repoService: GithubRepos


    fun getRepositories(): Single<List<Repo>> {
        return repoService.getRepos()
    }

    fun getSingleRepo(owner: String, name: String): Single<Repo> {
        return repoService.getSingleRepo(owner, name)
    }
   }

This is error i receive:

   Unable to start activity ComponentInfo{com.carllewis14.repos/com.carllewis14.repos.ui.MainActivity}: kotlin.UninitializedPropertyAccessException: lateinit property 
  repository has not been initialized
Caning answered 24/7, 2019 at 12:14 Comment(9)
you are accessing variable(repository) which must exist, but it is not initialized at a time, make it optional or initialize it before usageKneepad
You should inject your RepoRepository to your activity. Or inject MainActivityListViewModel and access your repo from viewmodel.Michel
@AlexandrKolesnik how do i initialize before usage is what i am askingCaning
@EnsarBayhan the MainActivityListViewModel is injected alreadyCaning
@Caning Yo have to inject to your MainActivity.Michel
@EnsarBayhan i have updated the MainActivityListViewModel above to show the main is already injected into main activityCaning
@Caning Did you add injection to your activity? Like this " AndroidInjection.inject(this)"Michel
@EnsarBayhan That reference doesnt appear in my ide i get an unresolved reference for that classCaning
@Caning You can follow this guide medium.com/@iammert/…Michel
H
4

have a look at my answer here (maybe it helps ) Nullable var with `?` vs. lateinit var

Essentially, you are never initializing your repository: RepoRepository.

From the code you have written, you won't need an instance of your repository in your activity as well, it should just be created in the constructor of your ViewModel (which has injection)

You are also going to have a similar issue with private lateinit var repoService: GithubRepos; if it's in the constructor of your object, you don't have to declare it again.

Hangbird answered 24/7, 2019 at 12:26 Comment(2)
just to clarify i wont need to inject repository: RepoRepository, in my activity because its injected into my viewmodel? so i should just have the viewmodel creation as viewModel = ViewModelProviders.of(this).get(MainActivityListViewModel::class.java) ? As if i include my viewmodelfactory like :` viewModel = ViewModelProviders.of(this, ViewModelFactory(repository)).get(MainActivityListViewModel::class.java)` then i have to add the instance as it appears in my viewmodel factory constructorCaning
ok let me try that and get back to you @Hangbird i appreciate the helpCaning
L
59

This is because you are trying to use the repository before initializing it with an instance without checking its initialization.

When using lateinit nullity cannot be used in that variable.

lateinit var repository: RepoRepository

Then, before using any method of the object, check that it is initialized:

if (::repository.isInitialized) {}

GL

Latoyia answered 21/8, 2019 at 18:41 Comment(2)
lateinit is not allowed on nullable typesMasticate
Then the isInitialized is like a null check. Why not using a nullable property for these cases?Quisling
A
6

if you're using Kotlin 1.2, you can easily check whether a lateinit variable has been initialized or not. If not, well, you can always use the not null approach.

Anyways, here's how you can check if a lateinit var has been initialized or not:

if (::fullName.isInitialized) {
    print("Hi, $fullName")
}
Allan answered 3/2, 2022 at 6:13 Comment(0)
H
4

have a look at my answer here (maybe it helps ) Nullable var with `?` vs. lateinit var

Essentially, you are never initializing your repository: RepoRepository.

From the code you have written, you won't need an instance of your repository in your activity as well, it should just be created in the constructor of your ViewModel (which has injection)

You are also going to have a similar issue with private lateinit var repoService: GithubRepos; if it's in the constructor of your object, you don't have to declare it again.

Hangbird answered 24/7, 2019 at 12:26 Comment(2)
just to clarify i wont need to inject repository: RepoRepository, in my activity because its injected into my viewmodel? so i should just have the viewmodel creation as viewModel = ViewModelProviders.of(this).get(MainActivityListViewModel::class.java) ? As if i include my viewmodelfactory like :` viewModel = ViewModelProviders.of(this, ViewModelFactory(repository)).get(MainActivityListViewModel::class.java)` then i have to add the instance as it appears in my viewmodel factory constructorCaning
ok let me try that and get back to you @Hangbird i appreciate the helpCaning
D
0

it seems the question code is shadowing the injection FYI you can also initialize by lazy :

To create an object that will be initialized at the first access to it, we can use the lazy method:

val lazyValue: ClassWithHeavyInitialization by lazy {
        numberOfInitializations.incrementAndGet()
        ClassWithHeavyInitialization()
    }

https://www.baeldung.com/kotlin-lazy-initialization also see kotlin docs

Donne answered 13/11, 2019 at 5:54 Comment(0)
O
0

Please make sure your dagger version should be updated.

enter image description here

https://github.com/google/dagger/releases

Oneill answered 26/2, 2024 at 15:3 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.