看到这篇文章(Square:从今天开始抛弃Fragment吧!),再想想刚入职网易的时候,花了近一个星期解决了一个有关fragment的坑,不禁十分感慨,我要对Fragment进行“控诉”。
1.getActivity()==null?
看下如下两段代码,在fragment中加上如下一个方法
public void asd(){ if(getActivity()==null){Log.d("yes","it is null");} }
然后在activity中加入fragment,如下:
FragmentTransaction transaction1 = getSupportFragmentManager().beginTransaction(); F1 f1 = new F1(); transaction1.replace(R.id.upperPart, f1); transaction1.commit(); f1.asd();
你觉得执行完asd会怎么样?答案是有可能返回null。因为commit是异步的,并不能保证commit之后fragment立刻执行onAttach(Activity activity)方法,并且onDetach之后执行这个方法结果也可想而知。
2.fragment重叠
一般大家用fragment都是动态添加的,但是fragment会像View一样被activity的onSaveInstanceState方法所保存,所以,当你的app被系统回收,然后你再次开启时,你的activity里面系统会恢复一个fragment。如果你的写法是这样的就会出现问题
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mFragment = new FragmentDemo(); FragmentManager fm = getFragmentManager(); FragmentTransaction tx = fm.beginTransaction(); tx.add(R.id.id_content, mFragment,"tag"); tx.commit(); }
你的id_content将会有两个FragmentDemo,新加的将会在以前恢复出来的上面也就是说的重叠。在屏幕旋转的时候也会出现重叠的情况。简单的解决办法是直接禁用onSaveInstanceState方法
@Override protected void onSaveInstanceState(Bundle outState) { // TODO Auto-generated method stub //super.onSaveInstanceState(outState); }
但是这个办法同时会禁用了其他view控件的状态保存,比如Edittext。这个时候就需要我们检测savedInstanceState是否为null,如果为null直接添加,不为null则保持对恢复的fragment的引用(如果不正确的恢复引用会爆NullPointerException),代码如下:
if(savedInstanceState == null) { //add fragment }else{ //don not add and find former fragment mFragment=(FragmentDemo)getSupportFragmentManager().findFragmentByTag("tag"); }
如果你不在乎性能,那么最简单暴力的解决办法就是把最开始的
tx.add(R.id.id_content, mFragment,"tag");
改为
tx.replace(R.id.id_content, mFragment,"tag");
这样不管你的savedInstanceState是否为null,而R.id.id_content这个Container里面永远只会有最新的那个fragment,而你也拿到的正确的引用。