Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

ViewModel and LiveData persist in destroyed fragment causing NPE on second access to fragment

I have a ViewModel that retrieves data from a single RxJava Observable using a Disposable.

internal class MyViewModel: ViewModel() {
   internal var disposable: Disposable? = null

   internal var myMutableLiveData= MutableLiveData<List<...>?>()

   internal fun getData(myParam: String) {
       disposable = (ApiServiceClient.createApiService().getDataFromAPI(
           myParam
    )).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
        { response -> myMutableLiveData.postValue(response) },{ myMutableLiveData.postValue(null) }
    )
   }
}

In my fragment, I observe myMutableLiveData in onViewCreated to retrieve the data. In onDestroyView of the fragment, I release resources.

internal class MyFragment: Fragment() {

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

private var _binding: FragmentMyBinding? = null
private val binding get() = _binding!!
private val viewModel: MyViewModel by viewModels()

override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View {
    _binding = FragmentMyBinding.inflate(inflater, container, false)
    return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    viewModel.myMutableLiveData.observe((context as MyActivity)) { data ->
        if (data == null) // Error
        else {
    // Success, use binding
        }
    }
    viewModel.getData("text")
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
    viewModel.disposable.dispose()
}

}

The first time I choose the fragment MyFragment, everything works fine. However, when I switch to another fragment within the same activity (MyFragment pass through onDestroyView, onDestroy and onDetach) and then I return to MyFragment (onCreate, onCreateView, onViewCreated), it seems as if the ViewModel is still there, causing the observation to happen before the binding class is reconstructed, resulting in a NullPointerException.

Why this? What is the correct way to manage the lifecycle of Fragment-ViewModel-Disposable?

>Solution :

While there might be some niche use cases to use Activity as the owner for the observer – your case seems to not be one.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    viewModel.myLiveData.observe(viewLifecycleOwner) { data ->
        if (data == null) {
            // Error
        } else {
            // Success, use binding
        }
    }
    viewModel.getData("text")
}

Also, it is not a good idea to expose mutable LiveData.

private val _myMutableLiveData = MutableLiveData<List<...>?>()
internal val myLiveData = _myMutableLiveData.asLiveData()

With a note that LiveData might return null if it is not being observed/hasn’t started yet.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading