Search code examples
androidviewmodel

Not able to understand viewmodel example on android dev site


class MyViewModel : ViewModel() {
    private val users: MutableLiveData<List<User>> by lazy {
        MutableLiveData().also {
            loadUsers()
        }
    }

    fun getUsers(): LiveData<List<User>> {
        return users
    }

    private fun loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}

Am trying to implement this way and its not compiling :

class MyViewModel : ViewModel() {
    private val users: MutableLiveData<List<String>> by lazy {
        return MutableLiveData().also {
            loadUsers()
        }
    }

    fun getUsers(): LiveData<List<String>> {
        return users
    }

    private fun loadUsers() {
        users.postValue(listOf("Tarun", "Chawla"))
    }
}

Mostly am not understanding the by lazy here. The example on android website seems wrong as loadUsers() is not returning anything which can be a delegate for users. can you please help me understanding above piece of code.

=======================================================

This is how I implemented:

    private val users : MutableLiveData<List<String>> by lazy {
        MutableLiveData<List<String>>().also {
            loadUsers(it)
        }
    }
    init {
        Log.e("Tarund", "View Model created")
    }

    override fun onCleared() {
        super.onCleared()
        Log.e("Tarund", "View Model deleted")
    }

    fun getUsers(): LiveData<List<String>> {
        return users
    }

    private fun loadUsers(users : MutableLiveData<List<String>>) {
        users.postValue(listOf("Tarun", "Chawla"))
    }
}

But if anyone can confirm if first example code above which I copy pasted from : https://developer.android.com/topic/libraries/architecture/viewmodel#kotlin is wrong


Solution

  • The code in the Android documentation is wrong.

    The lazy construction itself is fine: loadUsers() doesn't need to return anything because the function also is defined as:

    inline fun <T> T.also(block: (T) -> Unit): T
    

    that means that in here:

    private val sources: String by lazy {
        String().also {
          loadSources()
        }
    }
    

    the block also {} will return the empty String created with String() that can be assigned using lazy initialization to the val users

    The error trying to compile the Android docs code is:

    Type inference failed: Not enough information to infer parameter T in constructor MutableLiveData()

    that means that the compiler is not able to infer the type of the MutableLiveData instance created using the constructor wihtout type.

    Without the apply block the compiler will be able to compile it because it can easily infer the type from the val definition:

    private val sources: MutableLiveData<List<User>> by lazy {      
        MutableLiveData()
    }
    

    but adding the apply block goes back to the generic type and the compiler cannot infer it. So the solution, as you did, is specifying the type hold in the MutableLiveData container:

    private val sources: MutableLiveData<List<User>> by lazy { 
        MutableLiveData<List<User>>().also {
            loadSources()
        }
    }