2016-10-24 11:23:24 bitian123 阅读数 1534
  • Android开源项目实践之UI篇

    本课程主要展现了如何利用Android开源代码进行app的开发。例如: 1.异步网络请求(android-async-http); 2.百变圆形滚动条(ProgressWheel);3.滑动导航栏(PagerSlidingTabStrip);4.瀑布流与上拉刷新,下拉加载完美结合(PinterestLikeAdapterView)...

    21117 人正在学习 去看看 李忠义

有时候viewpager中的页面比较多,如果马上加载会很消耗资源,可以当用户切换到某个fragment时再加载。


在Fragment中有个


setUserVisibleHint(
boolean isVisibleToUser)方法


该方法用于告诉系统,这个Fragment的UI是否是可见的。所以我们只需要继承Fragment并重写该方法,即可实现在fragment可见时才进行数据加载操作,即Fragment的懒加载。

使用时,写一个基类LazyFragment,继承它即可,代码如下:
public abstract class BaseFragment extends Fragment {
    //是否可见
    protected boolean isVisible;
    // 标志位,标志Fragment已经初始化完成。
    public boolean isPrepared = false;

    /**
     * 实现Fragment数据的缓加载  
     * @param isVisibleToUser
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser); 
       if (getUserVisibleHint()) {
            isVisible = true; 
           onVisible();
        } else {
            isVisible = false;
            onInVisible();
        } 
   }
    protected void onInVisible() {
    }
    protected void onVisible() {
        //加载数据
        loadData();
    } 
   protected abstract void loadData();
}

在LazyFragment中增加了三个方法,一个是onVisible ,当fragment可见时调用。一个是onInvisible,当fragment不可见时调用。另外一个是loadData。

public class TabFragment extends LazyFragment{  

    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
        Log.d(LOG_TAG, "onCreateView");  
        View view = inflater.inflate(R.layout.fragment_tab, container, false);  
        //初始化view的各控件  
        isPrepared = true;  
        loadData();  
        return view;  
    }  

    @Override  
    protected void loadData() {  
        if(!isPrepared || !isVisible) {  
            return;  
        }  
        //填充各控件的数据  
    }  

}
Fragment生命周期中,setUserVisbleHint先于onCreateView执行。上面实例中,当TabFragment可见时,先进入loadData方法,当判断各控件未初始化完毕,则进入onCreateView方法,当控件初始化完毕后,会再次调用loadData。在loadData中判断isPrepared和isVisible,只要有一个不为true就不往下执行。因此,只有初始化完成并且fragment可见情况下,才会加载数据,这样就避免了未初始化带来的问题。



本文查自:http://www.jianshu.com/p/104be7cd72b6










2016-06-23 11:28:10 u014452224 阅读数 3932
  • Android开源项目实践之UI篇

    本课程主要展现了如何利用Android开源代码进行app的开发。例如: 1.异步网络请求(android-async-http); 2.百变圆形滚动条(ProgressWheel);3.滑动导航栏(PagerSlidingTabStrip);4.瀑布流与上拉刷新,下拉加载完美结合(PinterestLikeAdapterView)...

    21117 人正在学习 去看看 李忠义

使用ViewPager+Fragment的朋友应该知道其具有懒加载机制的,其实懒加载机制是Viewpager
所具有的,看过ViewPager源码的都会知道里面设置的有默认的懒加载的页数,默认的是1,这个1可不是我们通常所说的一页,这个1是左右各一页的意思。
这里写图片描述
比如说当进入应用时默认显示的是第一页,因为第一页左边没有要加载的页面,此时只会加载推荐和地图,如果你点击服务的时候,打印日志你就会发现此时加载的不再仅仅是服务,它会同时加载地图和客服共三个界面的数据。
下面是源码里面的懒加载的默认值
这里写图片描述
下面是默认进入界面为推荐页面时的日志:
这里写图片描述
当默认界面为服务的时候的日志:
这里写图片描述
通过日志可以发现默认的1其实一共是加载了三个界面的数据。那么我们如何解决懒加载的机制呢?
第一种方式就是把源码里面的Viewpager类里面的代码全部复制出来到自定义的一个类里面把默认值改为0即可。
为什么要自定义一个类而不是直接通过setOffscreenPageLimit(int limit)来设置为0呢?看源码你会发现,里面有一个关于limit参数的最小限制如果设置的参数小于1的话会赋值为默认值,仍是默认的1.所以建议自定义一个类,把默认值修改为0。如果设置的值大于1的话就可以直接使用setOffscreenPageLimit(int limit)此方法即可。

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

第二种方式就是重写 setUserVisibleHint这个方法。具体代码如下:

   @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
            // 相当于Fragment的onResume
        } else {
            // 相当于Fragment的onPause
        }

  }

点击免费下载示例代码

2017-06-01 00:43:56 qq_27540131 阅读数 746
  • Android开源项目实践之UI篇

    本课程主要展现了如何利用Android开源代码进行app的开发。例如: 1.异步网络请求(android-async-http); 2.百变圆形滚动条(ProgressWheel);3.滑动导航栏(PagerSlidingTabStrip);4.瀑布流与上拉刷新,下拉加载完美结合(PinterestLikeAdapterView)...

    21117 人正在学习 去看看 李忠义

前言:

最近在做项目优化,正好处理到这块,所以决定重新写篇细致点的关于fragment懒加载的博客。fragment的懒加载对于项目的性能也有优化作用,流量对于手机端而言还是蛮重要的虽然现在手机在很多时候所处于的网络环境都是使用wifi。当然你获取数据肯定要开启线程获取数据,这对于手机而言也是性能消耗。
好了,说了这么多废话该进入正题了,当然要懂一点fragment懒加载的,可以看我前期写的一篇博客
当然按照上面那篇博客那样处理还是不行的,或者说是细节还不够,所以接下来就说下在项目中具体怎么处理。
我这里就直接讲解demo如何处理了,一共是3个tab,先上一个basefragment的代码。再根据日志来讲解。
/**
 * 懒加载fragment
 */

public abstract class LazyLoadBaseFragment extends Fragment {
    protected boolean isVisible;
    private boolean isPrepared;
    private boolean isFirst = true;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        isPrepared = true;
        lazyLoad();
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (getUserVisibleHint()) {
            isVisible = true;
            lazyLoad();
        } else {
            isVisible = false;
            onInvisible();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    protected void lazyLoad() {
        if (!isPrepared || !isVisible || !isFirst) {
            return;
        }
        getData();
        isFirst = false;
    }

    protected void onInvisible() {


    }

    public abstract void getData();
}

从上面的代码可以看到,我这有3个标识,
1.isFirst---用于判断是否已经加载过数据了,用于缓存之后不再加载数据的
2.isVisible 在setUserVisibleHint(boolean isVisibleToUser)方法中判断fragment中的view已经显示没
3.isPrepared 判断fragment的onActivityCreated(Bundle saveInstanceState)方法是否已经被执行(为什么需要这个呢,后面分析的时候会说到)

由于这台机子没有运行环境(网络太慢升级有点麻烦),所以就直接拿在公司的测试时候的截图来说了。
正常情况下fragment从tab1滑动到tab2再滑动到tab3
tab3的fragment的日志情况

BalanceFragment就相当于我们的tab3
从上面的日志可以看到,setUserVisibleHint会先执行一次,然后当我们的tab3要执行onResume显示到前台的时候又会执行一次setUserVisibleHint,第一次不用说,getUserVisibleHint()拿到的值肯定是false,显示到前台之后才为true,这样我们再去拿数据.所以我刚开始的思路是,执行完oncreateview()之后再加上getUserVisibleHint()为true的时候才去获取数据。这样处理的话从tab1一直滑动到tab3是没有问题的。但是有种情况,从tab1直接点击到tab3就会出现问题了,原因是当页面显示tab1的时候,viewpager的默认机制是缓存下一个fragment和上一个fragment,所以tab2会被初始化,但是tab3就不会。看下图的Log日志就清楚了。

可以看到在tab3的onResume()执行之后并没有去执行setUserVisibleHint()方法,会直接在onCreate()之后就执行,与一开始的思路就相矛盾了,因为一开始的思路是执行完onCreateView()和setUserVisibleHint()方法返回true之后才去拿数据,因为在onCreateVIew()还没执行,setUserVisibleHint()就已经先返回true了,这样就会导致直接点击tab3不会调用获取数据的方法,导致页面一直停留在loading动画的页面。
所以这样我们的onActivityCreated()方法中的isPrepared标识就要起作用了,刚开始测试的时候忘记了打印onActivityCreated()回调的日志信息,不过看下面的日志信息就能懂了。

可以看到onCreateView()是执行在onActivityCreated()之后的,所以我们在onActivityCreated()中增加一个标识来判断fragment是否显示,显示就获取数据。相当于把onCreateView()的标识给替换到onActivityCreated()中。这样纵使是直接切换,setUserVisibleHint()执行在onCreateView()之前,我们也可以通过onActivityCreated()来判断是否是在fragment显示的时候才去获取数据。
其实这也是对fragment生命周期的一种理解与运用方式,所以很多时候基础还是很重要的。
这样就解决了,之前直接点击没有被viewpager提前缓存的fragment而出现不能加载数据的问题。
刚开始设计的错误思路的代码也贴下,这样方便理解




好了,fragment的懒加载就说到这里了,由于自己这台电脑跑demo跑不了,所以日志输出的图不太完美,不过相信仔细看下还是能懂的,如果要demo文章末尾有下载链接

懒加载Demo:

2018-05-31 19:43:33 Strange_Monkey 阅读数 276
  • Android开源项目实践之UI篇

    本课程主要展现了如何利用Android开源代码进行app的开发。例如: 1.异步网络请求(android-async-http); 2.百变圆形滚动条(ProgressWheel);3.滑动导航栏(PagerSlidingTabStrip);4.瀑布流与上拉刷新,下拉加载完美结合(PinterestLikeAdapterView)...

    21117 人正在学习 去看看 李忠义

为何懒加载

在很多 App 都会有ViewPage + Fragment 的基本组合,但是众所周知 viewPager预加载机制,即使设置函数 setOffscreenPageLimit(0) 也不能改变默认值为 1 的事实,这样最少也会加载 3 个fragment,无疑对 app 的性能有所影响。

何谓懒加载

所谓的懒加载,其实也就是延迟加载,就是等到该页面的UI展示给用户时,再加载该页面的数据(从网络、数据库等),而不是依靠ViewPager预加载机制提前加载两三个,甚至更多页面的数据.这样可以提高所属Activity的初始化速度,也可以为用户节省流量.而这种懒加载的方式也已经/正在被诸多APP所采用.

怎样懒加载

核心函数 : Fragment$setUserVisibleHint(boolean isVisibleToUser)Fragment$getUserVisibleHint()

实现的功能

  • 在 Fragment 不显示时,不进行页面加载。 此时则需要setUserVisibleHint(boolean isVisibleToUser)来进行获取是否可见标志。
  • 在 Fragment 没有创建完成时,不进行页面加载。此时需要 boolean hasCreate来标记 当前 Fragment 是否完成初始化,完成初始化则 hasCreatetrue
  • 根据当前 Fragment 是否需要初始化,添加标志位 boolean needInit,在当页面对用户可见并且当前页面还没有加载时,该标志位 needInit置位为 true, 当前页面在加载结束后标志位needInit 置位为 false

具体代码 基类 LazyFragment


    public boolean hasLoaded = false;  //标识是否已经加载过
    private boolean hasCreated = false; //标识onCreateView是否已调用
    private boolean needInit = false;   //标识是否需要在onCreateView中```

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        Log.i("lazy_load", "LazyFragment onCreateView. ");

        View rootView = inflater.inflate(R.layout.fragment_lazy, container, false);
        progressBar = $(rootView, R.id.fragment_lazy_progress_bar);
        content = $(rootView, R.id.fragment_lazy_content_wrapper);

        if (needInit) {
            initWrapper();
            needInit = false;
        }
        hasCreated = true;

        return rootView;
    }

    //首先执行,比onCreateView 早
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        Log.i("lazy_load", "LazyFragment setUserVisibleHint " + isVisibleToUser);
        Log.i("lazy_load", "LazyFragment setUserVisibleHint---- " + hasLoaded);

        if (isVisibleToUser && !hasLoaded) {    //如果当前Fragment向用户展示且没有加载过,进行下一步判断
            if (hasCreated) {   //如果onCreateView已经被创建,此时进行加载
                initWrapper();
            } else {        //如果Fragment没有创建,那么设置标记,在onCreateView中加载
                needInit = true;
            }
        }
    }

    /**
     * 此函数开始数据加载的操作,且仅调用一次
     */
    private void initWrapper() {

        LayoutInflater.from(getContext()).inflate(setContentView(), content);
        initialize();
        fadeOutView(progressBar, mShortAnimationDuration);
        fadeInView(content, mShortAnimationDuration);
        hasLoaded = true;
        Log.i("lazy_load", "LazyFragment initWrapper " + hasLoaded);
    }

    /**
     * 供子类使用,子类fragment初始化操作,此函数内部真正开始进行页面的一些列操作
     */
    abstract void initialize();

    /**
     * 子类fragment设置布局,返回fragment要设定的布局
     *
     * @return 子类fragment要显示的布局
     */
    @LayoutRes
    abstract int setContentView();

参考博客:

吴小龙同學 - Android ViewPager + Fragment 懒加载实现
ViewPager+Fragment组合的预加载和懒加载

其实该问题还涉及的有:

如何更新及替换ViewPager中的Fragment – 细节
Android Fragment的生命周期和返回栈

2016-09-29 17:57:30 lvzishen123 阅读数 2572
  • Android开源项目实践之UI篇

    本课程主要展现了如何利用Android开源代码进行app的开发。例如: 1.异步网络请求(android-async-http); 2.百变圆形滚动条(ProgressWheel);3.滑动导航栏(PagerSlidingTabStrip);4.瀑布流与上拉刷新,下拉加载完美结合(PinterestLikeAdapterView)...

    21117 人正在学习 去看看 李忠义
  1. 了解懒加载和普通加载的区别

    文章开头,先让我们了解一下什么是viewpager的懒加载。下面让两个对比动图来告诉我们普通的fragment+viewpager和使用了懒加载fragment+viewpager的区别所在:
    普通viewpager:
    这里写图片描述
    懒加载viewpager:
    这里写图片描述
    经过上边两个动图我们可以看出使用了懒加载的viewpager只有当被划到下一个页面的时候那个页面才会加载。而普通的viewpager如果你不使用setoffscreenpagelimit(int limit)这个方法去设置默认加载数的话是会默认加载页面的左右两页的(不了解这个方法的同学请先去百度一下这个方法了解一下用法和效果),也就是说当你进入viewpager第一页的时候第二页和第一页是会被一起加载的,这样同时加载就会造成一些问题,试想我们如果设置了setoffscreenpagelimit为3的话,那么进入viewpager以后就会同时加载4个fragment,像我们平时的项目中在这些fragment中一般都是会发送网络请求的,也就是说我们有4个fragment同时发送网络请求去获取数据,这样的结果显而易见给用户的体验是不好的(如:浪费用户流量,造成卡顿等等)。

  2. 实现懒加载分析

    这样我们就需要使用viewpager的懒加载机制去让被浏览页面只有被用户可见的时候再会完成加载操作。接着来介绍一下fragment的setUserVisibleHint方法,这也是此实现最重要的一个方法,来让我们看下关于这个方法的介绍:

  * 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.
     *
     * <p>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.</p>
     *
     * @param isVisibleToUser true if this fragment's UI is currently visible to the user (default),
     *                        false if it is not.
     */
    public void setUserVisibleHint(boolean isVisibleToUser) {
        if (!mUserVisibleHint && isVisibleToUser && mState < STARTED
                && mFragmentManager != null && isAdded()) {
            mFragmentManager.performPendingDeferredStart(this);
        }
        mUserVisibleHint = isVisibleToUser;
        mDeferStart = mState < STARTED && !isVisibleToUser;
        }

可以看到该方法用于告诉系统,这个Fragment的UI是否是可见的。也就是说当Fragment被显示在屏幕时,setUserVisibleHint的isVisibleToUser参数为true,不显示时为fasle。所以我们只需要围绕这个方法即可完成fragment的懒加载。那就让我们先写一个看看。

public abstract class BasePagerFragment extends Fragment {

    protected AppCompatActivity mActivity;

    protected boolean isVisibleToUser; //页面是否可见



    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {   //page 1等会此读数据  生命周期
        super.setUserVisibleHint(isVisibleToUser);
        this.isVisibleToUser = isVisibleToUser;
        prepareFetchData();
    }



    public abstract void loadData();


    protected void prepareFetchData() {
        if (isVisibleToUser) {
            loadData();
        }
    }


}

这么写乍一看好像是没有问题,请接着往下看。
好的,让我们再来看下viewpager加载fragment时fragment的生命周期,直接上代码:

public class MainActivity extends AppCompatActivity {
    ViewPager viewPager;
    List<Fragment> fragmentList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewPager = (ViewPager) findViewById(R.id.viewpager_id);
        Fragment payOrderFragment = DemoFragment.newInstance("0", "");
        Fragment unPayOrderFragment = DemoFragment.newInstance("1", "");
        Fragment payOrderHistoryFragment = DemoFragment.newInstance("2", "");
        fragmentList.add(payOrderFragment);
        fragmentList.add(unPayOrderFragment);
        fragmentList.add(payOrderHistoryFragment);
        viewPager.setOffscreenPageLimit(2);  //fragmentList.size()-1
        MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), (ArrayList<Fragment>) fragmentList);
        viewPager.setAdapter(adapter);
    }

    public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
        ArrayList<Fragment> list;

        public MyFragmentPagerAdapter(FragmentManager fm, ArrayList<Fragment> list) {
            super(fm);
            this.list = list;

        }


        @Override
        public int getCount() {
            return list.size();
        }

        @Override
        public Fragment getItem(int arg0) {
            return list.get(arg0);
        }

        @Override
        public int getItemPosition(Object object) {
            return super.getItemPosition(object);
        }


    }
}
public abstract class BasePagerFragment extends Fragment {

    protected AppCompatActivity mActivity;


}
public class DemoFragment extends BasePagerFragment {
    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";
    private  String TAG="";

    // TODO: Rename and change types of parameters
    private String mParam1;
    private String mParam2;

    ImageView imageview;

    public DemoFragment() {
        // Required empty public constructor
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @param param2 Parameter 2.
     * @return A new instance of fragment DemoFragment.
     */
    // TODO: Rename and change types and number of parameters
    public static DemoFragment newInstance(String param1, String param2) {
        DemoFragment fragment = new DemoFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(TAG,"onCreate");
    }
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
        if(mParam1.equals("0")){
            TAG="0";
        }else if(mParam1.equals("1")){
            TAG="1";
        }else {
            TAG="2";
        }
        Log.e(TAG,"isVisibleToUser"+isVisibleToUser);
        super.setUserVisibleHint(isVisibleToUser);
    }

//    @Override
//    protected void prepareFetchData(boolean forceUpdate) {
//        super.prepareFetchData(true);
//    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        Log.e(TAG,"onCreateView");
        View view = inflater.inflate(R.layout.fragment_demo, container, false);
        imageview = (ImageView) view.findViewById(R.id.imageview);
        imageview.setImageResource(R.mipmap.ic_launcher);
        return view;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.e(TAG,"onActivityCreated");
    }



    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
        if(mParam1.equals("0")){
            TAG="0";
        }else if(mParam1.equals("1")){
            TAG="1";
        }else {
            TAG="2";
        }
        mActivity = (AppCompatActivity) context;
        Log.e(TAG,"onAttach");
    }


    @Override
    public void onStart() {
        super.onStart();
        Log.e(TAG,"onStart");
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.e(TAG,"onStop");
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.e(TAG,"onDestroyView");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG,"onDestroy");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Log.e(TAG,"onDetach");
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.e(TAG,"onResume");
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.e(TAG,"onPause");
    }
}

如上图所示代码很简单,就是3个fragment加载到viewpager中,fragment通过tag区分不用的fragment对象方便我们观察生命周期log,当我们运行代码后的生命周期为:
这里写图片描述

可以看到首先第一个首先运行的是第一个fragment的setUserVisibleHint方法,因为第一个fragment的值可见,所以参数为true,但是我们会发现这个方法是在第一个fragment被加载前被调用的,如果你只在按照我们初识那么写的话,当它走到loaddata()中的时候控件view并没有初始化,这样肯定会造成空指针问题。既然如此我们让它控件加载后再读取数据即可,控件初识化一般在oncreateview方法中,所以我们在fragment的onActivityCreated方法中再去加载即可,改造后如下:

public abstract class BasePagerFragment extends Fragment {

    protected AppCompatActivity mActivity;
    protected boolean isViewInitiated; //控件是否初始化完成
    protected boolean isVisibleToUser; //页面是否可见



    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {   //page 1等会此读数据  生命周期
        super.setUserVisibleHint(isVisibleToUser);
        this.isVisibleToUser = isVisibleToUser;
        prepareFetchData();
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {   //page 0进入再此读数据
        super.onActivityCreated(savedInstanceState);
        isViewInitiated = true;
        prepareFetchData();
    }

    public abstract void loadData();


    protected void prepareFetchData() {
        if (isVisibleToUser && isViewInitiated ) {
            loadData();
        }
    }


}

好的,这样我们遍完成了viewpager的懒加载,这时又会出现一个问题,加入当我们翻到第二页的时候,setUserVisibleHint便又会被置为true,如图最下方:
这里写图片描述
这也就会造成已经加载过的页面又被加载一次的局面,这时我们就可以声明一个标志位来告诉改界面是否已经加载过数据,如下:

public abstract class BasePagerFragment extends Fragment {

    protected AppCompatActivity mActivity;
    protected boolean isViewInitiated; //控件是否初始化完成
    protected boolean isVisibleToUser; //页面是否可见
    protected boolean isDataInitiated; //数据是否加载


    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {   //page 1等会此读数据  生命周期
        super.setUserVisibleHint(isVisibleToUser);
        this.isVisibleToUser = isVisibleToUser;
        prepareFetchData(false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {   //page 0进入再此读数据
        super.onActivityCreated(savedInstanceState);
        isViewInitiated = true;
        prepareFetchData(false);
    }

    public abstract void loadData();


    protected void prepareFetchData(boolean forceUpdate) {
        if (isVisibleToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) {
            loadData();
            isDataInitiated = true;
        }
    }


}

可以看到我们加标志位的同时加入了一个forceUpdate参数,这个参数是由我们控制的,默认为false,我们可以复写这个方法将它改为true,当我们改为true之后每次重新划到该页面的时候便会重新加载一遍数据以便满足实时更新等需求。
如下:

@Override
    protected void prepareFetchData(boolean forceUpdate) {
        super.prepareFetchData(true);
    }

最后如有不足请小伙伴们提出,感谢大家的观看,完整代码我已经放到github上了,如有需要请下载,谢谢大家!!
https://github.com/lvzishen/ViewPagerLazyLoad/tree/master

ListView懒加载

阅读数 668

没有更多推荐了,返回首页