I try to update MutableList's value within LiveData by function "addToArray". But I get null, when I try to observe liveData into a fragment. What's happening? Please, any Advice?! May be, I need to change a type within LiveData?! But, what should I choose? I use ViewModelFactory for initialize viewModel.
class MainViewModel(private val point: Int, private val index: Int) : ViewModel() {
private var _arrayOne = MutableLiveData<MutableList<Int?>?>()
val arrayOne: LiveData<MutableList<Int?>?> = _arrayOne
fun addToArray(index: Int, point: Int) {
val value = _arrayOne.value
value?.add(point)
_arrayOne.value = value
Log.d("ViewModel", "$value")
}
private lateinit var binding: FragmentMainBinding
private var point = 0
private var index = 0
private val viewModelFactory: MainViewModelFactory by lazy {
MainViewModelFactory(point, index)
}
private val viewModel by lazy {
ViewModelProvider(this, viewModelFactory)[MainViewModel::class.java]
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val array = initializeFirstParticipant()
for (item in array) {
item.setOnEditorActionListener { textView, i, keyEvent ->
if (textView.text.toString().isEmpty()) {
textView.setBackgroundResource(R.drawable.background_outlined_red)
Toast.makeText(requireContext(), "Enter valid value!", Toast.LENGTH_SHORT)
.show()
true
} else {
val point = Integer.parseInt(textView.text.toString())
val index = array.indexOf(item)
viewModel.addToArray(index, point)
Log.d("MainFragment", "Index is $index, value is $point")
viewModel.arrayOne.observe(viewLifecycleOwner, Observer {
Log.d("MainFragment", "Array is $it")
})
textView.setBackgroundResource(R.drawable.background_outlined)
false
}
}
}
}
/* Return array of view for editing score for first participant */
fun initializeFirstParticipant(): Array<TextView> {
val tvArray = arrayOf<TextView>(
binding.partOnePointTwo,
binding.partOnePointThree,
binding.partOnePointFour,
binding.partOnePointFive,
binding.partOnePointSix,
binding.partOnePointSeven
)
return tvArray
}
}`
I try to set Array instead List type Within LiveData, but it didn't help. May be, I need to use another type within LiveData?!
You never actually created a MutableList to put in your LiveData. Notice you never called mutableListOf
or arrayListOf()
anywhere in your code?
There is also rarely a need to make the type of a LiveData nullable, especially with Lists, because you can use empty lists to represent there being no data. Avoid nullable stuff wherever possible, because it makes code more difficult to work with. (In Java we avoid nullability because it makes code fragile, i.e. crash-prone. Kotlin fixed the fragility by enforcing null checks, but this makes nullable variables harder to handle correctly.)
You should also make the type of the list non-nullable if you can help it.
So, I would first change it as follows:
private var _arrayOne = MutableLiveData<MutableList<Int>>(mutableListOf())
val arrayOne: LiveData<MutableList<Int>> = _arrayOne
However, I also want to mention, it is generally a bad idea to use a MutableList in a LiveData for a couple of reasons:
So it is much preferable to use a read-only List instead. So you can update your code to:
class MainViewModel(private val point: Int, private val index: Int) : ViewModel() {
private var _arrayOne = MutableLiveData<List<Int>>(emptyList())
val arrayOne: LiveData<List<Int>> = _arrayOne
fun addToArray(index: Int, point: Int) {
_arrayOne.value = _arrayOne.value.orEmpty() + point
Log.d("ViewModel", "$value")
}
The orEmpty()
above is an easy way to handle the fact that LiveData.value
always returns a nullable even if the type isn't nullable. In this case, we know it's never null, but I like to avoid using !!
.