51

I am using live data in my application for all the network calls and response handling.

In one of the scenarios, my recycler view is loading some data in its view holder's onBind and the response is updating the UI. In order to do so, I have to provide a lifecycleOwner to the observer.

As recycler view doesn't have any lifecycle owner of its own, I am using the parent fragment for that by using parentFragment.viewlifecycleOwner but somehow it is giving an error.

How can a view Holder have its instance when the parent fragment is not having its instance?

viewModel.responseState.observe(parentFragment.viewLifecycleOwner, Observer {
    updateUI(it)
})

Fatal Exception: java.lang.IllegalStateException: Can't access the Fragment View's LifecycleOwner when getView() is null i.e., before onCreateView() or after onDestroyView()

Teasel
  • 1,330
  • 4
  • 18
  • 25
Utkarsh Singh
  • 511
  • 1
  • 4
  • 3
  • 4
    The problem was that my ViewHolder was fetching some data from the server and after the response was received the actual data for the holder was created, which again had some observers which were attached using the parent fragment's lifecycle owner. But if I navigated away from the fragment while my viewholder was fetching the data, the parent fragment view was destroyed, and when the viewholder got the response and tried attaching the observer with the parent fragment's lifecycle owner, it throws the above-mentioned error as there was no view left with the parent fragment. – Utkarsh Singh Nov 21 '19 at 11:05

13 Answers13

15

This can be fixed, by triggering the logic which is raising the error, from around end of onCreateView(...) callback (not onCreate(...) nor onAttach(...)).

In getViewLifecycleOwner() documentation, I don't think, I can explain better:

The first method where it is safe to access the view lifecycle is onCreateView(LayoutInflater, ViewGroup, Bundle) under the condition that you must return a non-null view (an IllegalStateException will be thrown if you access the view lifecycle but don't return a non-null view).

The view lifecycle remains valid through the call to onDestroyView(), after which getView() will return null, the view lifecycle will be destroyed, and this method will throw an IllegalStateException. Consider using getViewLifecycleOwnerLiveData() or FragmentTransaction.runOnCommit(Runnable) to receive a callback for when the Fragment's view lifecycle is available.

public LifecycleOwner getViewLifecycleOwner() {
    if (mViewLifecycleOwner == null) {
        throw new IllegalStateException("Can't access the Fragment View's LifecycleOwner when "
                + "getView() is null i.e., before onCreateView() or after onDestroyView()");
    }
    return mViewLifecycleOwner;
}
Top-Master
  • 7,611
  • 5
  • 39
  • 71
pandey_shubham
  • 423
  • 5
  • 14
9

i faced the same problem and i could fix it with the code bellow , just check if the view is null or not

     if ( view != null)
       viewModel.responseState.observe(parentFragment.viewLifecycleOwner, Observer {
       updateUI(it) })
Abdev
  • 301
  • 2
  • 7
4

The solution for me was writing code inside onViewCreated insted of writing in onCreateView.... and my problem fixed.

1

The problem is that the observer is still active on the parent's viewLifecycleOwner even after the view is destroyed (when you navigate to the next fragment). The most reliable way to fix this is to clear out the observers.

override fun onDestroyView()
    viewModel.responseState.removeObservers(parentFragment.viewLifecycleOwner)
    super.onDestroyView()
}
acarrell
  • 11
  • 2
0

The solution for me was simplified. I am using separate observers - one for the network which is using Lifecycleowner from the main activity (or just from any activity) and one for the fragment view (model view view model).

0
 myModel.getOfflineData().observeForever(new Observer<List<indiaStateModel>>() {
                @Override
                public void onChanged(List<indiaStateModel> indiaStateModels) {
                    adapter = new stateAdapter(indiaStateModels);
                    recyclerView.setAdapter(adapter);
                }
            });

// use this forever observer when your are getting that error // mainly this error comes when you try to change your phone theme to dark to light or light to dark

0

Best To Use FLow() instead of LiveData()

Convert LiveData() to Flow()

Before

viewModel.responseState.observe(parentFragment.viewLifecycleOwner, Observer {
    updateUI(it)
})

AFTER

lifecycleScope.launch {

viewModel.responseState.asFlow().collectLatest{
 
updateUI(it)

l̥

}

}
  • If you have a new question, please ask it by clicking the [Ask Question](https://stackoverflow.com/questions/ask) button. Include a link to this question if it helps provide context. - [From Review](/review/late-answers/29817703) – Rishabh Deep Singh Sep 14 '21 at 08:34
0

In my case I was setting observer inside view runnable:

view.post(() ->{
    ...
    viewModel.getDate().observe();
})
Te Global
  • 3
  • 3
0

I used as suggested by android studio viewLifecycleOwnerLiveData. so for your case will be something like

    parentFragment.viewLifecycleOwnerLiveData.value?.let { nonNullViewLifecycleOwner -> 
       viewModel.responseState.observe(nonNullViewLifecycleOwner, Observer   {
          updateUI(it)
       })
    }

Hope it helps!

Njuacha Hubert
  • 388
  • 3
  • 14
0

observe view model live data in onViewCreated function. Or you can do this check this out

Viroth
  • 429
  • 5
  • 14
0

I resolved this by making sure I was clearing all my subscriptions inside the onDestroyView() of my Fragment than in the onDestroy(). This totally fixed it ! My code was trying to access the view after the onDestroyView() was called.

Roehit Kadam
  • 101
  • 1
  • 11
-2

The solution, as your comment, is to ensure the fragment's view is not null. This happened to me with a Fragment inside a ViewPager.

Emmanuel Guerra
  • 1,372
  • 1
  • 12
  • 20
-3
override fun onDestroyView()
    viewModel.responseState.removeObservers(parentFragment.viewLifecycleOwner)
    super.onDestroyView()
}

Check if there view is Destroy then Lifecycle Owner cant perform of updating UI so it is getting crash

so stop the action if on View has Destroy
  • 1
    Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes. – Mark Rotteveel Apr 01 '23 at 09:02