CoderUni
CoderUni

Reputation: 6144

MutableLiveData ArrayList is empty even after postValue() Kotlin

I am now stuck and currently wondering why my mutable arraylist returns null even if it is being updated with postvalue(). I tried to display it using Toast and it displayed [] which I think is null. It had no space in between so it looked like a box. I did toString() it as well in order to show the text. How would I be able to solve this problem?

Here is my Main Activity:

val list = ArrayList<String>()
list.add("text1")
list.add("text2")
val viewmodel = ViewModelProviders.of(this).get(viewmodel::class.java)
viewmodel.Testlist.postValue(list)

ViewModel:

class viewmodel: ViewModel() {
    val Testlist: MutableLiveData<ArrayList<String>> = MutableLiveData()
    init {
        Testlist.value = arrayListOf()
    }
}

Fragment:

Top area:

activity?.let {
    val viewmodel = ViewModelProviders.of(this).get(viewmodel::class.java)
    observeInput(viewmodel)
}

Bottom area:

private fun observeInput(viewmodel: viewmodel) {
    viewmodel.Testlist.observe(viewLifecycleOwner, Observer {
        it?.let {
            Toast.makeText(context, it.toString(), Toast.LENGTH_LONG).show()
        }
    })
}

Upvotes: 2

Views: 11434

Answers (4)

Ashok Kumar
Ashok Kumar

Reputation: 1271

Probably you can see developer guide example to resolve your problem

https://developer.android.com/topic/libraries/architecture/viewmodel.html#kotlin

// shared viewmodel

 class SharedViewModel : ViewModel() {
    private val usersList: MutableLiveData<List<String>>()

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

    fun setUsers(users: List<String>) {
        usersList.value = users
    }
 }

// Attach ViewModel In Activity onCreate()

val model = ViewModelProviders.of(this)[SharedViewModel::class.java]

val list = arrayListOf<String>()
list.add("user1")
list.add("user2")

model.setUsers(list)

// Get same ViewModel instance In fragment onCreateView()

model = activity?.run {
        ViewModelProviders.of(this)[SharedViewModel::class.java]
} ?: throw Exception("Invalid Activity")

model.getUsers().observe(this, Observer<List<User>>{ users ->
      // update UI
})

Upvotes: 2

nt95
nt95

Reputation: 595

have you used the same instance of your view model? or have you defined another view model in the fragment class? The issue could be that you're accessing a different instance of the view model and not the one were the MutableLiveData was updated

Upvotes: 1

jsamol
jsamol

Reputation: 3232

You post the value to the LiveData object in the activity's viewmodel, which isn't the same instance as the fragment's viewmodel. Let's take look at the way you instantiate the viewmodel in your fragment:

activity?.let {
    // activity can be refered by the implicit parameter `it`
    // `this` refers to the current fragment hence it's the owner of the view model
    val viewmodel = ViewModelProviders.of(this).get(viewmodel::class.java)
    observeInput(viewmodel)
}

To get a viewmodel that is shared between your activity and fragment you have to pass the activity as its owner:

activity?.let { val viewmodel = ViewModelProviders.of(it).get(viewmodel::class.java) }

Upvotes: 4

z85510
z85510

Reputation: 43

You can use this :

    fun <T : Any?> MutableLiveData<ArrayList<T>>.default(initialValue: ArrayList<T>) = apply { setValue(initialValue) }

and then use this function as below:

    viewmodel.Testlist.default(ArrayList())

For me, I have a BaseActivity that other activities extend from it :

class UAppCompatActivity : AppCompatActivity() {

    protected fun <T : Any?> MutableLiveData<ArrayList<T>>.default(initialValue: ArrayList<T>) = apply { setValue(initialValue) }

    protected fun <T> MutableLiveData<ArrayList<T>>.addItem(item: T) {
        val updatedItems = this.value as ArrayList
        updatedItems.add(item)
        this.value = updatedItems
    }

    protected fun <T> MutableLiveData<ArrayList<T>>.deleteItem(item: T) {
        val updatedItems = this.value as ArrayList
        updatedItems.remove(item)
        this.value = updatedItems
    }

    ...

Upvotes: 1

Related Questions