首页 > 代码库 > ILJMALL project过程中遇到Fragment嵌套问题:IllegalArgumentException: Binary XML file line #23: Duplicate id

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");
        }
    }
}

 

 
 

ILJMALL project过程中遇到Fragment嵌套问题:IllegalArgumentException: Binary XML file line #23: Duplicate id