Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> ILJMALL project過程中遇到Fragment嵌套問題:IllegalArgumentException: Binary XML file line #23: Duplicate id,

ILJMALL project過程中遇到Fragment嵌套問題:IllegalArgumentException: Binary XML file line #23: Duplicate id,

編輯:關於android開發

ILJMALL project過程中遇到Fragment嵌套問題:IllegalArgumentException: Binary XML file line #23: Duplicate id,


  • 出現場景:當點擊“分類”再返回“首頁”時,發生error退出
 
  • BUG描述:Caused by: java.lang.IllegalArgumentException: Binary XML file line #23: Duplicate id 0x7f0d0054, tag null, or parent id 0xffffffff with another fragment for com.example.sxq123.iljmall.FragmentCatagorySpace
 
  • //framgment_home.xml
 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ScrollView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1">
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text = "@string/home"/>

<fragment
    android:id = "@+id/fragment_space"
    android:name = "com.example.sxq123.iljmall.FragmentCatagorySpace"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

</LinearLayout>
</ScrollView>
</LinearLayout>

 

 
  • //FragmentHome.java
public class FragmentHome extends Fragment {

    private View view;
    FragmentCatagorySpace fragmentCatagorySpace ;

    @Override
    public View onCreateView(LayoutInflater inflater , ViewGroup container , Bundle savedInsataceState){
        view = inflater.inflate(R.layout.fragment_home, null);
        Log.d(this.getClass().getName(),"  onCreateView() Begin");
        initChildFragment();

        return view;
    }
    private void initChildFragment(){
        Log.d("-------------------","init space ");
        fragmentCatagorySpace = (FragmentCatagorySpace)getChildFragmentManager().findFragmentById(R.id.fragment_space);
        if(fragmentCatagorySpace != null){
            Log.d("----------------","init space success and no null");
        }
    }
}

 

   
  • 問題原因
http://www.tuicool.com/articles/FNVN3i   activity中不同的frament之間項目替換的時候,FragmentManager只會remove和add這些frament, 然而這些frament裡面自己加載的frament(這裡就是我們的FragmentCatagorySpace)是沒有被remove. 很顯然這是一個缺陷! 因為後一個frament(FragmentCatagorySpace)很明顯是依賴與他的父frament的,應該同時遞歸的remove.   那麼如何解決這個問題呢!很顯然就是在不用這個frament(FragmentHome)的時候把他裡面加載的frament給remove掉! 這個操作在Fragment的重新onCreateView() inflate layout之前remove掉就可以解決問題了! 比如將remove的事務放在父Fragment的onDestroyView()之中執行  
  • 修正後的代碼
 
public class FragmentHome extends Fragment {

    private View view;
    FragmentCatagorySpace fragmentCatagorySpace ;

    @Override
    public View onCreateView(LayoutInflater inflater , ViewGroup container , Bundle savedInsataceState){
        view = inflater.inflate(R.layout.fragment_home, null);
        Log.d(this.getClass().getName(),"  onCreateView() Begin");
        initChildFragment();

        return view;
    }
@Override
public void onDestroyView(){
    super.onDestroyView();
    if(fragmentCatagorySpace != null){
        Log.d("-------------------", "space no null");
        FragmentManager fragmentManager = getFragmentManager();
        if(fragmentManager != null && !fragmentManager.isDestroyed()){
            final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction ();
            if(fragmentTransaction != null){
                fragmentTransaction.remove(fragmentCatagorySpace).commit();
                //commit()和commitAllowingStateLoss()都是先發送到主線程任務隊列中, 當主線程准備好了再執行,異步。
                // //如果沒有在inflate之前執行remove child fragmetn 的transaction,將會發生duplicate id 的exception !!!
//                fragmentTransaction.commit();//可以放在onCreateView中執行commit(),但偶爾會發生onSaveInstanceState()之後不能執行commit()的沖突
                fragmentTransaction.commitAllowingStateLoss();
                //立即執行任務隊列中的transaction, 不異步 !!!!!!!!!!!!!!!重點!!!!!!!!!!!!!!!!!!!!
//防止remove事務被加到主線程任務隊列中,那這樣異步的話可能這些事物直到父Fragment重新執行onCreateView()
//之前都沒有執行完,同樣會發生duplicate id 的異常
//如果這些remove 的食物放在父Fragment的onSaveInstanceState()中執行, 由於onSaveInstanceState()調用並不
//是每一個Fragment生命周期都會被調用(????),所以偶爾也會發生duplicate id  的異常
 fragmentManager.executePendingTransactions();
                Log.d("------------------","  space destroy");
            }
        }
    }
}
    private void initChildFragment(){
        Log.d("-------------------","init space ");
        fragmentCatagorySpace = (FragmentCatagorySpace)getChildFragmentManager().findFragmentById(R.id.fragment_space);
        if(fragmentCatagorySpace != null){
            Log.d("----------------","init space success and no null");
        }
    }
}

 

   

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved