0

I'm making an app using the MVVM pattern.

I am implementing a function to add an item to the recycler view when a button is clicked, but I get a NullPointException error from the observer. (To be precise, you press a button to switch screens and add items based on the received argument.)

What went wrong..?

I referenced this

In Fragment

override fun onViewCreated(view: View, savedInstanceState
: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        args.workout?.let {
            viewModel.addItem()
        }

        viewModel.item.observe(viewLifecycleOwner) { newItem ->
            adapter.setItems(newItem) // error
        }
    }

ViewModel

class WriteRoutineViewModel : ViewModel() {
    private var _item: MutableLiveData<ArrayList<RoutineModel>> = MutableLiveData()
    val item: LiveData<ArrayList<RoutineModel>> = _item

    fun addItem() {
        _item.value?.add(RoutineModel("test", "ABC"))
        _item.value = _item.value
    }
}

ERROR

2021-07-15 04:26:25.961 13731-13731/com.example.writeweight E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.writeweight, PID: 13731
    java.lang.NullPointerException: newItem must not be null
        at com.example.writeweight.fragment.WriteRoutineFragment$onViewCreated$4.onChanged(WriteRoutineFragment.kt:66)
        at com.example.writeweight.fragment.WriteRoutineFragment$onViewCreated$4.onChanged(WriteRoutineFragment.kt:18)
        at androidx.lifecycle.LiveData.considerNotify(LiveData.java:133)
        at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:146)
        at androidx.lifecycle.LiveData$ObserverWrapper.activeStateChanged(LiveData.java:468)
        at androidx.lifecycle.LiveData$LifecycleBoundObserver.onStateChanged(LiveData.java:425)
        at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
        at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:265)

ybybyb
  • 1,385
  • 1
  • 12
  • 33

1 Answers1

3

The issue here is, MutableLiveData<ArrayList<RoutineModel>> is set to just MutableLiveData(), try changing it to MutableLiveData(arrayListOf()) it should work :)

EDIT:

The reason is simple, the ArrayList requires to be initialised even inside the MutableLiveData wrapper around it.

mehul bisht
  • 682
  • 5
  • 15
  • 1
    No, either you can check everytime inside the `add()` method if the `_item.value != null` and only then add the item, else initialise it with `_item = arrayListOf()` since it doesn't get initialised on it's own, and in case you understood it, kindly mark my answer as accepted solution :) – mehul bisht Jul 14 '21 at 19:47
  • Haha.. I was writing to ask why this is, but you corrected the answer to this! So, apart from initializing `MutableLiveData`, `ArrayList` should also be initialized, right? – ybybyb Jul 14 '21 at 19:49
  • 1
    yes, basically anything inside the `MutableLiveData` wrapper needs to be initialised before using it's value :) – mehul bisht Jul 14 '21 at 19:50
  • OK, I understand that part. So, why doesn't the `_item.value?.add(RoutineModel("test", "ABC"))` step throw an error? `ArrayList` inside `MutableLiveData` is uninitialized, why doesn't `add()` throw an error? – ybybyb Jul 14 '21 at 19:52
  • 2
    LiveData.value returns a nullable version of the value. The returned value is null if the initial value has not been set yet. When you use the nullsafe call operator `?.` and the value is null, `add` is not called because there is nothing to call it on. – Tenfour04 Jul 14 '21 at 19:54
  • 1
    @Tenfour04 oh! The problem was the safety call! Now I get it right. Thank you so much. I'm still far away. Have a nice day – ybybyb Jul 14 '21 at 19:57