Fragment - should I reuse view in onCreateView and how should I do that?
Asked Answered
S

3

15

Actually, I always reused my view in my fragments like the following:

private View mView = null;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    if (mView == null)
        mView = inflater.inflate(R.layout.view);
    return mView;
}

That worked, with viewpager and so on. Now I started using my fragments in simple activities as well and if, and only if, I add the fragment to the backstack, this will fail because of java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

So my questions are:

  • Is it ok, if I check the the views parent, remove it and add it to the new parent?
  • Or should I always recreate the view and never reuse it? If yes, why?
  • Are there other points, where reusing the view will fail?
Salty answered 5/9, 2013 at 13:3 Comment(0)
N
14

Maybe this can help to understand the behavior. If you check out FragmentManagerImpl.java you will find the following:

First we create a view by calling onCreateView() (line 845) and then we wrap created view with another view, which becomes a parent of our view (lines 848-849). This means our view does not become a child of real container, but it's a child of a wrapper view now. The problem with reuse happens, when view gets removed from the container (line 998). FragmentManager removes wrapper view from the container, but our real view stays added to the parent wrapper view. This is what causes the issue you experience.

Thus, if you remove the view from its parent, it can work. Even knowing this, I would not recommend reusing views in the fragment also because views can live a bit longer than fragments, because they can be used in "disappearing" animations even after the fragment is been destroyed. If you try to remove such a view from its parent at that time, then the animation might be broken.

Another argument to not cache the view is that Android doesn't support view recycling in fragments by design. Remember ListAdapter allowing to reuse the views? Android takes care for caching and proper reusing those views. This is not the case with fragment though.

Niela answered 5/9, 2013 at 14:36 Comment(0)
C
8

I'm currently reusing the view with something like this:

if(view == null){
    view = (ViewGroup) inflater.inflate(R.layout.news_list, container, false);
} else {
    ((ViewGroup) view.getParent()).removeView(view);
}
return view;

I don't know if this way is correct, but it seems to work for me..

NOTE: I'm using this aproach because I have a listview in a fragment, and when user tap on an item it loads a new fragment (fragment manager replace current list fragment using). Then, when user hit backbutton, as I'm reusing the same old view of the fragment (that is not destroyed when removed with FM) then the user continues viewing the list in the position it was before opening detail fragment view.

Colwell answered 7/5, 2014 at 13:31 Comment(1)
Hi @edrain your solution works fine but it is not removing the view from the container even i have popped my fragment.Godlike
A
0

I know it's a old question. But after working with fragments for months, I found one thing need to mention when using cache this way is that: if your current cached layout still has another fragment tag, this cache strategy will lead to the embed fragment loss some life-cycle callback. I'll talk it in detail:

  1. The current fragment onCreateView was called first time. By caching like above, we will inflate the target layout(this layout including a fragment tag).
  2. By inflater.inflate this will make the embed fragment added to the layout correctly, the onCreateView will be called.
  3. When current fragment needs to be destroy, the embed fragment onDestroyView will be called correctly.
  4. When current fragment onCreateView called again, we return a cached view, without calling inflater.inflate. You will find the embed fragment onCreateView and onDestroyView or other life-cycle methods won't be called.

That's all what I want to mention.

Antakiya answered 10/5, 2018 at 3:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.