美文网首页
关于Fragment与ViewPager,PageAdapter

关于Fragment与ViewPager,PageAdapter

作者: RookieRun | 来源:发表于2019-01-31 17:11 被阅读9次

Fragment相关:

1.懒加载

1.懒加载需要解决的问题:
    1.Fragment一般配合ViewPager使用,所以,有可能所有Fragment同时初始化并加载数据,想一下,如果Fragmen较多时,如果不加控制,则会在性能上面造成很大的影响。
  2.解决思路:
     1.使用ViewPager的setOffscreenPageLimit(int limit )方法限制,用来限制预加载的View的个数,可行,但是limit 小于1时,无效

 public void setOffscreenPageLimit(int limit) {
        if(limit < 1) {
            Log.w("ViewPager", "Requested offscreen page limit " + limit + " too small; defaulting to " + 1);
            limit = 1;
        }
        if(limit != this.mOffscreenPageLimit) {
            this.mOffscreenPageLimit = limit;
            this.populate();
        }
    }

2.Fragment中有个方法:setUserVisibleHint(boolean isVisibleToUser) ,然而这个方法在某些情况下也是有坑的,比如和PageAdapter配合使用的时候,setUserVisibleHint就不会被调用,具体的坑,我们下面介绍
2.生命周期重复走
这个问题也是项目中遇到的,具体表现是,每次切换tab时,Fragment的生命周期都会从onCreate开始重新走一次,这对于时效性要求不高的界面来说,同样是浪费(即时时效性高,也不应该以重回的方式刷新数据。。。
原来的场景是,Fragment嵌套Fragment,然后,onResume的时候,去重新replace某个fragment,而replace的时候,又是new Fragment
这就谈到了Fragment的使用方式,到底是add/show/hide还是replace,二者分别在什么场景用呢?
1.replace方式:
网上好多帖子说,replace会导致Fragment的生命周期重绘,这里有一个前提就是该Fragment是否是一个新的实例,如果是以下的办法,则不会重回,而是回调OnStart,onResume
replace方式,就类似于一山不容二虎,同一时间,在container中只能由1个fragment实例存在,而这种方式也不会出现重叠的情况,但是可能会导致生命周期重绘

这是某个Activity的onResume
    @Override
    protected void onResume() {
        super.onResume();
        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
        if (testFragment == null) {//如果这里没有判空,而是每次都去new,那么原来的Fragment会完整走完生命周期至onDetach,而新的Fragment也同样会onAttached->...->onResume
            testFragment = new TestFragment();
        }
        fragmentTransaction.replace(R.id.container, testFragment).commit();
    }

2.add方式
add方式是container中存在多个Fragment实例,然后,通过show/hide方式使对应的fragment切换到前后台,轮番登场

 FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
                    Fragment fragmentByTag = getSupportFragmentManager().findFragmentByTag("right");
                    if (fragmentByTag != null && fragmentByTag instanceof RightFragment) {
                        rightFragment = ((RightFragment) fragmentByTag);
                        fragmentTransaction.show(rightFragment);
                    } else {
                        rightFragment = new RightFragment();
                        fragmentTransaction.add(R.id.container, rightFragment, "right");
                    }
                    if (testFragment!=null){
                        fragmentTransaction.hide(testFragment);
                    }
                    fragmentTransaction.commit();

Fragment重叠的问题
Fragment的重叠,主要出现在以下场景:
1.通过FragmentTransaction .add方式管理Fragment,但是,在显示Fragment时,未把其他Fragment隐藏
2.系统内存不足时,进程被杀,应用缓存数据后又重新恢复数据
3.旋转屏幕后,出现重叠
4.开发者选项,不保留活动

3.setUserVisibleHint不调用

这主要表现在Fragment和PageAdapter配合使用时,该方法不被调用
  1.setUserVisibleHint执行时机
首先看下官网的解释:请注最后一句的Note:大意是说,此方法可能会在Fragment的生命周期之外被调用,所以,不能保证此方法的调用顺序回合Fragment的生命周期关联起来

Set a hint to the system about whether this fragment's UI is currently visible to the user.
This hint defaults to true and is persistent across fragment instance state save and restore.
An app may set this to false to indicate that the fragment's UI is scrolled out of visibility or is otherwise not directly visible to the user. This may be used by the system to prioritize operations such as fragment lifecycle updates or loader ordering behavior.
Note: This method may be called outside of the fragment lifecycle. and thus has no ordering guarantees with regard to fragment lifecycle method calls.
从Log来看,这个方法会优先于其他生命周期执行,而且会执行两次,Fragment实例是通过new方法实例出来的

02-03 11:30:18.427 4672-4672/com.rookie.mywanandroid E/KnowledgeListFragment.java: --->(KnowledgeListFragment.java:152)===>false<---isVisibleToUser--->KnowledgeListFragment{4aae094c id=0x7f0800e9 android:switcher:2131230953:0}
02-03 11:30:18.427 4672-4672/com.rookie.mywanandroid E/KnowledgeListFragment.java: --->(KnowledgeListFragment.java:152)===>true<---isVisibleToUser--->KnowledgeListFragment{4aae094c id=0x7f0800e9 android:switcher:2131230953:0}
02-03 11:30:18.427 4672-4672/com.rookie.mywanandroid E/KnowledgeListFragment.java: --->(KnowledgeListFragment.java:122)===>60<---onCreateView--->KnowledgeListFragment{4aae094c #0 id=0x7f0800e9 android:switcher:2131230953:0}
02-03 11:30:18.427 4672-4672/com.rookie.mywanandroid E/KnowledgeListFragment.java: --->(KnowledgeListFragment.java:169)===>onViewCreated--->KnowledgeListFragment{4aae094c #0 id=0x7f0800e9 android:switcher:2131230953:0}
02-03 11:30:18.427 4672-4672/com.rookie.mywanandroid E/KnowledgeListFragment.java: --->(KnowledgeListFragment.java:181)===>onStart--->KnowledgeListFragment{4aae094c #0 id=0x7f0800e9 android:switcher:2131230953:0}
02-03 11:30:18.427 4672-4672/com.rookie.mywanandroid E/KnowledgeListFragment.java: --->(KnowledgeListFragment.java:187)===>onResume--->KnowledgeListFragment{4aae094c #0 id=0x7f0800e9 android:switcher:2131230953:0}

2.为什么使用PageAdapter管理fragment时,setUserVisibleHint不会执行,而使用FragmentPageAdapter和FragmentStatePageAdapter切换tab时,会执行该方法
由源码可以看到,主要是instantiateItem和setPrimaryItem方法影响的,而setPrimaryItem这个方法又会在ViewPager 的populate方法中调用,而populate方法又是ViewPager显示的重要方法,这一连串下来就导致了3个Adapter的不同表现
源码->PageAdapter

 @Deprecated
    public void setPrimaryItem(@NonNull View container, int position, @NonNull Object object) {
    //这里只是一个空实现
    }

源码->FragmentPageAdapter


 public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        Fragment fragment = (Fragment)object;
        if(fragment != this.mCurrentPrimaryItem) {
            if(this.mCurrentPrimaryItem != null) {
                this.mCurrentPrimaryItem.setMenuVisibility(false);--->当前的fragment不是要显示的,则回调false
                this.mCurrentPrimaryItem.setUserVisibleHint(false);;--->当前的fragment不是要显示的,则回调false
            }

            fragment.setMenuVisibility(true);;--->当前的fragment是要显示的,则回调true
            fragment.setUserVisibleHint(true);;--->当前的fragment不是要显示的,则回调true
            this.mCurrentPrimaryItem = fragment;
        }

    }

源码->FragmentStatePageAdapter

  public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        Fragment fragment = (Fragment)object;
        if(fragment != this.mCurrentPrimaryItem) {
            if(this.mCurrentPrimaryItem != null) {
                this.mCurrentPrimaryItem.setMenuVisibility(false);
                this.mCurrentPrimaryItem.setUserVisibleHint(false);
            }

            fragment.setMenuVisibility(true);
            fragment.setUserVisibleHint(true);
            this.mCurrentPrimaryItem = fragment;
        }

    }

4.与onHiddenChanged关系

以add/show/hide方式管理Fragment时,已经存在/创建的Fragment,在hide方法调用时,onHiddenChanged(boolean hidden)调用,并且hidden为true,
对于正在show的Fragment,,onHiddenChanged(boolean hidden)也调用,并且hidden为false;
但是,setUserVisibleHint(boolean isVisible)却没有调用

5.POSITION_UNCHANGED与POSITION_NONE的区别
6.PageAdapter,FragmentPageAdapter,FragmentStatePageAdapter使用与区别

相关文章

网友评论

      本文标题:关于Fragment与ViewPager,PageAdapter

      本文链接:https://www.haomeiwen.com/subject/zoclsqtx.html