question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Fragments create new instances of Observers after onActivityCreated

See original GitHub issue

First of all I want to say thanks for the three samples which enlighten working with these new components significantly, looking at the code there is a lot to learn.

After trying to create a project, making use of the new arch components, I noticed that one of my Fragments received more and more events from LiveData within the Observer code after navigating back and forth in the UI.

This happens due to the Fragment instance being retained and popped back from the stack after “back” navigation.

In these examples typically in onActivityCreated LiveData is observed and a new Observer is created. In order to solve recreating new Observers, checking if onActivityCreated has been called on the instance of Fragment before seems to be the goto solution for the moment.

@yigit how would you go about this? check if savedInstanceState is null and then create Observers? I also noticed that declaring the Observers as final fields seems to solve the issue as well, meaning that registering the same Observer instance several times seems to be fine, is this something you would recommend?

Thanks a lot and keep up the good work! Manuel

UPDATE 12 Oct 2019

using viewLifecycleOwner as LifecycleOwner as proposed seems to solve my issue. Typically what I do now is the following:

class MainFragment : Fragment() {
// ... declare viewmodel lazy
    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel.liveData.observe(viewLifecycleOwner, Observer { item ->
           // ... code that deals with item / state goes here
        })
    }
//...
}

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:29
  • Comments:57 (11 by maintainers)

github_iconTop GitHub Comments

43reactions
cbeylscommented, Oct 23, 2017

After some thinking I realized fragments actually provide 2 distinct lifecycles:

  • The lifecycle of the fragment itself
  • The lifecycle of each view hierarchy.

My proposed solution is to create a fragment which allows accessing the lifecycle of the current view hierarchy in addition to its own.

/**
 * Fragment providing separate lifecycle owners for each created view hierarchy.
 * <p>
 * This is one possible way to solve issue https://github.com/googlesamples/android-architecture-components/issues/47
 *
 * @author Christophe Beyls
 */
public class ViewLifecycleFragment extends Fragment {

	static class ViewLifecycleOwner implements LifecycleOwner {
		private final LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);

		@Override
		public LifecycleRegistry getLifecycle() {
			return lifecycleRegistry;
		}
	}

	@Nullable
	private ViewLifecycleOwner viewLifecycleOwner;

	/**
	 * @return the Lifecycle owner of the current view hierarchy,
	 * or null if there is no current view hierarchy.
	 */
	@Nullable
	public LifecycleOwner getViewLifeCycleOwner() {
		return viewLifecycleOwner;
	}

	@Override
	public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
		super.onViewCreated(view, savedInstanceState);
		viewLifecycleOwner = new ViewLifecycleOwner();
		viewLifecycleOwner.getLifecycle().handleLifecycleEvent(Event.ON_CREATE);
	}

	@Override
	public void onStart() {
		super.onStart();
		if (viewLifecycleOwner != null) {
			viewLifecycleOwner.getLifecycle().handleLifecycleEvent(Event.ON_START);
		}
	}

	@Override
	public void onResume() {
		super.onResume();
		if (viewLifecycleOwner != null) {
			viewLifecycleOwner.getLifecycle().handleLifecycleEvent(Event.ON_RESUME);
		}
	}

	@Override
	public void onPause() {
		if (viewLifecycleOwner != null) {
			viewLifecycleOwner.getLifecycle().handleLifecycleEvent(Event.ON_PAUSE);
		}
		super.onPause();
	}

	@Override
	public void onStop() {
		if (viewLifecycleOwner != null) {
			viewLifecycleOwner.getLifecycle().handleLifecycleEvent(Event.ON_STOP);
		}
		super.onStop();
	}

	@Override
	public void onDestroyView() {
		if (viewLifecycleOwner != null) {
			viewLifecycleOwner.getLifecycle().handleLifecycleEvent(Event.ON_DESTROY);
			viewLifecycleOwner = null;
		}
		super.onDestroyView();
	}
}

It can be used to register an observer in onActivityCreated() that will be properly unregistered in onDestroyView() automatically:

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
	super.onActivityCreated(savedInstanceState);

	viewModel.getSampleData().observe(getViewLifeCycleOwner(), new Observer<String>() {
		@Override
		public void onChanged(@Nullable String result) {
			// Update views
		}
	});
}

When the fragment is detached and re-attached, the last result will be pushed to the new view hierarchy automatically as expected.

@yigit Do you think this is the right approach to solve the problem in the official library?

26reactions
cbeylscommented, Jun 7, 2018

The proper fix is to use Fragment.getViewLifecycleOwner() which is already part of AndroidX.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Multiple LiveData Observers After Popping Fragment
The HomeFragment is using the navigation component to launch a new child Fragment ProfileFragment. On back press the ProfileFragment is popped ...
Read more >
Observe LiveData from ViewModel in Fragment - Medium
Since FragmentA is never destroyed, the previous Observer is never removed. As a result, each time onActivityCreated was called, a new Observer ......
Read more >
Fragment lifecycle - Android Developers
The fragment's view Lifecycle is created only when your Fragment provides a valid View instance. In most cases, you can use the fragment...
Read more >
Where to register observers for livedata in fragment? What are ...
You can register them in onCreateView or onViewCreated. if you want to bound the view model to the activity you need to do...
Read more >
5 common mistakes when using Architecture Components
we will wind up passing a new identical instance of Observer every time the fragment is re-attached, but LiveData won't remove previous ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found