嵌套Fragment的使用及遇到The specified child already has a parent. You must call removeView()问题的解决


嵌套Tab在Android应用中用途广泛,之前做过的一些东西都是运用了TabActivity。但是由于在Android Developers中说到了“TabActivity was deprecated in API level 13." ,并且建议大家使用Fragment。所以学习了嵌套Fragment的使用,参考了这个博客中的相关思路和代码。

 


在Android Developers中对于Fragment(中文版看这里)的描述:A Fragment represents a behaviors or a portion of user interface in an Activity. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running.
简单来说,Fragment就是被嵌入在Activity中用来表现UI的一个可模块化和可重用的组件。Fragment在大屏幕设备中应用可以非常广泛,开发者可以通过自己巧妙的设计让UI更加灵活和美观。

 

创建Fragment
创建Fragment,必须创建一个Fragment的子类。
创建一个自己的Fragment,需要创建一个Fragment的子类。Fragment的生命周期和Activity的生命周期类似,它包含了很多与Activity类似的回调函数。

[java]
public void onCreate (Bundle savedInstanceState) 

public void onCreate (Bundle savedInstanceState)创建fragment的时候调用onCreate()方法
[java]
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 

public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)在第一次绘制UI的时候系统调用该方法,为了绘制UI,返回一个fragment布局的根View。

 


将Fragment添加到Activity的方法
1.在layout文件中声明fragment


[plain]
<FrameLayout 
      android:id="@+id/fragment_container" 
      android:layout_width="fill_parent" 
      android:layout_height="0dip" 
      android:layout_weight="1.0" 
      android:background="#fffab3" > 
  </FrameLayout> 

  <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1.0"
        android:background="#fffab3" >
    </FrameLayout>

 

2.将一个fragment添加到viewgroup中,使用FragmentTransaction添加、替换或者删除fragment。

 

[java]
private void addFragmentToStack(Fragment fragment) { 
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
        ft.replace(R.id.fragment_container, fragment); 
        ft.commit(); 
    } 

private void addFragmentToStack(Fragment fragment) {
  FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
  ft.replace(R.id.fragment_container, fragment);
  ft.commit();
 }Fragment生命周期


异常分析

 

关于解决 java.lang.IllegalStateException The specified child already has a parent. You must call removeView()的方法

 嵌套Fragment的使用及遇到The specified child already has a parent. You must call removeView()问题的解决_第1张图片

在运行调试的时候会发现,在第二次点击一个相同的tab的时候,会出现上述异常。

这个异常说的是,这个特定的child view已经存在一个parent view了,必须让parent view调用removeView()方法。

经过对fragment的生命周期的分析


运行顺序:点击tab1,点击tab2,再点击tab1.

具体fragment的生命周期是:

 

 嵌套Fragment的使用及遇到The specified child already has a parent. You must call removeView()问题的解决_第2张图片


对上图进行分析,可以发现,出问题的是viewpager中的view。当切换不同的viewpager(即fragment,每个fragment中装载了一个viewpager)时,调用了startActivity()方法的时候,传入了相同的id,会返回相同的对象。而当我们在第二次调用的时候,传入了相同的id是复用了原来的view,这就导致了view被指定多个parent view。

所以解决办法就是,在使用这个view之前首先判断其是否存在parent view,这调用getParent()方法可以实现。如果存在parent view,那么就调用removeAllViewsInLayout()方法。代码如下:

 

[java]
for (View view : viewList) { 
            ViewGroup p = (ViewGroup) view.getParent(); 
            if (p != null) { 
                p.removeAllViewsInLayout(); 
            } 
        } 

你可能感兴趣的:(嵌套Fragment的使用及遇到The specified child already has a parent. You must call removeView()问题的解决)