美文网首页
ViewPager切换防止Fragment销毁以及取消Fragm

ViewPager切换防止Fragment销毁以及取消Fragm

作者: 程序员学园 | 来源:发表于2017-04-04 00:29 被阅读0次

    存在的问题

    1. 默认情况下,ViewPager会自动预加载
    2. 切换过程中会销毁fragment视图

    下面的图说明情况

    Paste_Image.png

    如图,在Activity中使用ViewPager嵌套三个Fragment,当fragment1出现的时候,此时会预加载fragment2,滑动到fragment2会预加载fragment3,但是滑动到fragment3,此时会调用fragment1的destroyview方法,销毁视图。当重新滑动到fragment1才会重新调用fragment1的oncreateview方法。注意此时并不会销毁实例,不会调用ondestroy方法。

    这样就存在两个问题

    1、pagerview频繁切换,导致fragment1.fragment3在频繁的调用destroyview和oncreateview方法,重新创建视图。这样也浪费了大量的资源,用户体验不佳,虽然内存消耗比较低

    2、因为切换到fragment1的时候,同时预加载了fragment2,如果此时fragment2也有大量的耗时网络请求要做,如果应用对启动反应速度比较敏感,所以此时做了多余的工作。或者说fragment2也会显示加载进度,显然不符合我们的预期,能否把这些耗时的工作延迟加载,也是个问题

    防止频繁的销毁视图的解决方案

    1、setOffscreenPageLimit(2)
    2、或者重写PagerAdaper的destroyItem方法为空即可
    笔者此处使用的是方案2

    public class MyViewPagerAdapter extends FragmentPagerAdapter {
    
            ...
    
            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                //如果注释这行,那么不管怎么切换,page都不会被销毁
                //super.destroyItem(container, position, object);
            }
        }
    

    取消预加载解决方案

    介绍两个方法void setUserVisibleHint(boolean isVisibleToUser)、boolean getUserVisibleHint(),它们分别用作设置/获得Fragment可见状态,我们可以重写Fragment在其中做判断。

    第一步:重写Fragment

    public abstract class BaseFragment extends Fragment{
    
    
        /** Fragment当前状态是否可见 */
        protected boolean isVisible;
    
        public void onCreate(android.os.Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        }
    
        @Override
        public void setUserVisibleHint(boolean isVisibleToUser) {
            super.setUserVisibleHint(isVisibleToUser);
    
            if(getUserVisibleHint()) {
                isVisible = true;
                onVisible();
            } else {
                isVisible = false;
                onInvisible();
            }
        }
    
        /**
         * 可见
         */
        protected void onVisible() {
            lazyLoad();
        }
        
        /**
         * 不可见
         */
        protected void onInvisible() {
        }
    
        /**
         * 延迟加载
         * 子类必须重写此方法
         */
        protected abstract void lazyLoad();
    }
    

    第二步:继承BaseFragment

    1、声明二个重要的变量

    private boolean mHasLoadedOnce = false;
    private boolean isPrepared = false;
    

    2、onCreateView中进行控件初始化,初始化完成后加载数据

     @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_layuot2, null);
            Dbug.d("","Fragment2==onCreateView");
            initData();
            isPrepared = true;
            lazyLoad();
            return view;
        }
    
    

    此处为什么要用isPrepared呢,因为lazyLoad();方法调用的时候控件可能没初始化完成,会报空指针错误。

    3、lazyLoad中判断是否是首次加载和初始化完成

     @Override
        protected void lazyLoad() {
            if (mHasLoadedOnce || !isPrepared)
                return;
            mHasLoadedOnce = true;
        }
    

    4、onDestroyView中变量重置

     @Override
        public void onDestroyView() {
            super.onDestroyView();
            Dbug.d("","Fragment2==onDestroyView");
            mHasLoadedOnce = false;
            isPrepared = false;
        }
    

    相关文章

      网友评论

          本文标题:ViewPager切换防止Fragment销毁以及取消Fragm

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