ViewModel not detaching observer and causing nullpointerexceptions

Viewed 154

This is a weird bug I have, I started to think that the observer of my fragment is still observing after I popped up that fragment.

So, I have two fragments that use the same viewmodel, but they don't share it with the activity, the viewmodel instance is for each fragment

FragmentB()

   private val viewModel by viewModels<OrderViewModel> { VMOrderFactory(
            OrderRepoImpl(
                OrderDataSource()
            )
        ) }
  ...

           viewModel.fetchOrderStatus(trackingDetails.orderId).observe(viewLifecycleOwner, Observer { result -> ... }

Now, I use from FragmentA() Flow coroutines to keep updates in realtime in my view.

OrderViewModel

 fun fetchOrderStatus(orderId: String) = liveData(Dispatchers.IO){
        emit(Resource.Loading())
        try{
            repo.getOrderStatus(orderId).collect { status ->
                emit(status)
            }
        }catch (e:Exception){
            emit(Resource.Failure(e))
        }
    }

Now, this is the situation

When I'm in FragmentA() this works and fetches the orders.

Now, If I go to FragmentB() and comeback again to FragmentA() and try to delete from FragmentA() with the other instance of this viewmodel and another method, the fetchOrderStatus from FragmentB() gets executed and since I poped this fragment it returns a nullPointerException

So, its weird that with viewLifeCycleOwner this observer is not detached from FragmentB() when coming back to FragmentA() and another weird thing is that this just happens when I rapidly come back from FragmentB() to FragmentA() and try to delete an order, but If I wait a little bit (2 or 3 seconds until the flow attaches and request the data) this works normally

What could be happening and whats happening with my observers?

FragmentA()

Fragment A does not use the method fetchOrderStatus from FragmentB()

 private val viewModel by viewModels<OrderViewModel> { VMOrderFactory(
            OrderRepoImpl(
                OrderDataSource()
            )
        ) }

 viewModel.deleteOrder(adapter.getItem(position).orderId).observe(viewLifecycleOwner, Observer { result -> ... }

The error is thrown here, but is not about the deleteOrder method but instead from the FragmentB() fetchOrderStatus method, and that's weird because at this point FragmentB() was popped and its methods should not fetch any data.

Maybe I need to kill the flow when popping this fragmentB , but I'm doing it at the datasource method when it fetches and delivers with

  awaitClose { subscription.remove() }
1 Answers

If you create ViewModel and provide Fragment context then the ViewModel is destroyed when Fragment is destroyed. If you want the ViewModel to outlive the fragments, then you need to start it with activity context activityViewModel()

Related