FragmentPagerAdapter与FragmentStatePagerAdapter那些秘密的事



总结:



1.添加/替换fragment视图有两种方法getSupportFragmentManager().beginTransaction().replace(R.id.contain,new Fragment1()).commit();

和getSupportFragmentManager().beginTransaction().add(R.id.contain,new Fragment1()).commit();


2.replace相当于remove+add所以会将原来fragment销毁掉(视图销毁+fragment销毁),add只是添加到容器不会销毁视图和fragment对象。add配合hidden和show使用,可以在app首页用于tab切换这样不会像replace那样来回切换销毁视图销毁fragment,重建fragment对系统开销大。
3.但是如果fragment添加了回退栈setBackStack(null)在使用replace方法时,这个时候视图会销毁但是fragment对象不会销毁。

4.当fragment和viewpage一起使用的时候时,viewpage默认保存3个fragment对象(即当前,当前左,当前右),当滑动超过第三个时如果adapter是fragmentPageAdapter第一个fragment的视图会销毁(对象不会销毁);如果adapter是fragmentStatePageAdapter时第一个frament视图和对象都销毁。

5.fragment比较少的时候(比如只有3,4个)选取viewpager+FragmentPagerAdapter的组合,当fragment比较多(大于3,4个)这个时候选取viewpager+FragmentStatePagerAdapter的方式来实例化fragment。

6.修改viewpage默认保存fragment保存个数用viewpage.setOffscreenPageLimit(int count)方法  
7.fragment添加了回退栈setBackStack(null)进入新的frament,在新的fragment里面想返回到之前fragment可以用getSupportFragmentManager().popBackStack()方法
8.fragment的getactivity为null,解决办法

可能你遇到过getActivity()返回null,或者平时运行完好的代码,在“内存重启”之后,调用getActivity()的地方却返回null,报了空指针异常。

大多数情况下的原因:你在调用了getActivity()时,当前的Fragment已经onDetach()了宿主Activity。
比如:你在pop了Fragment之后,该Fragment的异步任务仍然在执行,并且在执行完成后调用了getActivity()方法,这样就会空指针。

解决办法:
更"安全"的方法:(对于Fragment已经onDetach这种情况,我们应该避免在这之后再去调用宿主Activity对象,比如取消这些异步任务,但我们的团队可能会有粗心大意的情况,所以下面给出的这个方案会保证安全)

在Fragment基类里设置一个Activity mActivity的全局变量,在onAttach(Activity activity)里赋值,使用mActivity代替getActivity(),保证Fragment即使在onDetach后,仍持有Activity的引用(有引起内存泄露的风险,但是异步任务没停止的情况下,本身就可能已内存泄漏,相比Crash,这种做法“安全”些),即:

protected Activity mActivity;
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    this.mActivity = activity;
}

/**
*  如果你用了support 23的库,上面的方法会提示过时,有强迫症的小伙伴,可以用下面的方法代替
*/
@Override
public void onAttach(Context context) {
    super.onAttach(context);
    this.mActivity = (Activity)context;
}

Fragment重叠异常-----正确使用hide、show的姿势

如果你add()了几个Fragment,使用show()、hide()方法控制,比如微信、QQ的底部tab等情景,如果你什么都不做的话,在“内存重启”后回到前台,app的这几个Fragment界面会重叠。

原因是FragmentManager帮我们管理Fragment,当发生“内存重启”,他会从栈底向栈顶的顺序一次性恢复Fragment;
但是因为没有保存Fragment的mHidden属性,默认为false,即show状态,所以所有Fragment都是以show的形式恢复,我们看到了界面重叠。
(如果是replace,恢复形式和Activity一致,只有当你pop之后上一个Fragment才开始重新恢复,所有使用replace不会造成重叠现象)

解决方案:可以给给一个fragment添加默认白色背景

还有一种场景,addreplace都有可能造成重叠: 在onCreate中加载Fragment,并且没有判断saveInstanceState==null,导致重复加载了同一个Fragment导致重叠。(PS:replace情况下,如果没有加入回退栈,则不判断也不会造成重叠,但建议还是统一判断下)

@Override 
protected void onCreate(@Nullable Bundle savedInstanceState) {
// 在页面重启时,Fragment会被保存恢复,而此时再加载Fragment会重复加载,导致重叠 ;
    if(saveInstanceState == null){
       // 正常情况下去 加载根Fragment 
    } 
}


Fragment与Activity之间的交互
•Fragment与Activity之间的交互可以通过Fragment.setArguments(Bundle args)以及Fragment.getArguments()来实现。

Fragment状态的持久化。
由于Activity会经常性的发生配置变化,所以依附它的Fragment就有需要将其状态保存起来问题。下面有两个常用的方法去将Fragment的状态持久化。

•方法一:◦可以通过protected void onSaveInstanceState(Bundle outState),protected void onRestoreInstanceState(Bundle savedInstanceState) 状态保存和恢复的方法将状态持久化。

•方法二(更方便,让Android自动帮我们保存Fragment状态):

◦我们只需要将Fragment在Activity中作为一个变量整个保存,只要保存了Fragment,那么Fragment的状态就得到保存了,所以呢.....◾FragmentManager.putFragment(Bundle bundle, String key, Fragment fragment) 是在Activity中保存Fragment的方法。
◾FragmentManager.getFragment(Bundle bundle, String key) 是在Activity中获取所保存的Frament的方法。

◦很显然,key就传入Fragment的id,fragment就是你要保存状态的fragment,但,我们注意到上面的两个方法,第一个参数都是Bundle,这就意味着FragmentManager是通过Bundle去保存Fragment的。但是,这个方法仅仅能够保存Fragment中的控件状态,比如说EditText中用户已经输入的文字(注意!在这里,控件需要设置一个id,否则Android将不会为我们保存控件的状态),而Fragment中需要持久化的变量依然会丢失,但依然有解决办法,就是利用方法一!
◦下面给出状态持久化的事例代码:

     /** Activity中的代码 **/
     FragmentB fragmentB;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_activity);
        if( savedInstanceState != null ){
            fragmentB = (FragmentB) getSupportFragmentManager().getFragment(savedInstanceState,"fragmentB");
        }
        init();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        if( fragmentB != null ){
            getSupportFragmentManager().putFragment(outState,"fragmentB",fragmentB);
        }

        super.onSaveInstanceState(outState);
    }

    /** Fragment中保存变量的代码 **/

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        AppLog.e("onCreateView");
        if ( null != savedInstanceState ){
            String savedString = savedInstanceState.getString("string");
            //得到保存下来的string
        }
        View root = inflater.inflate(R.layout.fragment_a,null);
        return root;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putString("string","anAngryAnt");
        super.onSaveInstanceState(outState);
    }







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值