嵌套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()的方法

 

在運行調試的時候會發現,在第二次點擊一個相同的tab的時候,會出現上述異常。

這個異常說的是,這個特定的child view已經存在一個parent view瞭,必須讓parent view調用removeView()方法。

經過對fragment的生命周期的分析

運行順序:點擊tab1,點擊tab2,再點擊tab1.

具體fragment的生命周期是:

 

 

對上圖進行分析,可以發現,出問題的是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(); 
            } 
        } 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。