Android基础:Fragment,看这篇就够了 ( 下 )

作者:夏正冬

《Android 基础:Fragment,看这篇就够了 (上)》

ViewPager+Fragment相关

基本使用

ViewPager是support v4库中提供界面滑动的类,继承自ViewGroup。PagerAdapter是ViewPager的适配器类,为ViewPager提供界面。但是一般来说,通常都会使用PagerAdapter的两个子类:FragmentPagerAdapter和FragmentStatePagerAdapter作为ViewPager的适配器,他们的特点是界面是Fragment。

在support v13和support v4中都提供了FragmentPagerAdapter和FragmentStatePagerAdapter,区别在于:support v13中使用android.app.Fragment,而support v4使用android.support.v4.app.Fragment。一般都使用support v4中的FragmentPagerAdapter和FragmentStatePagerAdapter。

默认,ViewPager会缓存当前页相邻的界面,比如当滑动到第2页时,会初始化第1页和第3页的界面(即Fragment对象,且生命周期函数运行到onResume()),可以通过setOffscreenPageLimit(count)设置离线缓存的界面个数。

FragmentPagerAdapter和FragmentStatePagerAdapter需要重写的方法都一样,常见的重写方法如下:

  • public FragmentPagerAdapter(FragmentManager fm): 构造函数,参数为FragmentManager。如果是嵌套Fragment场景,子PagerAdapter的参数传入getChildFragmentManager()
  • Fragment getItem(int position): 返回第position位置的Fragment,必须重写。
  • int getCount(): 返回ViewPager的页数,必须重写。
  • Object instantiateItem(ViewGroup container, int position): container是ViewPager对象,返回第position位置的Fragment。
  • void destroyItem(ViewGroup container, int position, Object object): container是ViewPager对象,object是Fragment对象。
  • getItemPosition(Object object): object是Fragment对象,如果返回POSITION_UNCHANGED,则表示当前Fragment不刷新,如果返回POSITION_NONE,则表示当前Fragment需要调用destroyItem()instantiateItem()进行销毁和重建。 默认情况下返回POSITION_UNCHANGED

懒加载

懒加载主要用于ViewPager且每页是Fragment的情况,场景为微信主界面,底部有4个tab,当滑到另一个tab时,先显示”正在加载”,过一会才会显示正常界面。

默认情况,ViewPager会缓存当前页和左右相邻的界面。实现懒加载的主要原因是:用户没进入的界面需要有一系列的网络、数据库等耗资源、耗时的操作,预先做这些数据加载是不必要的。

这里懒加载的实现思路是:用户不可见的界面,只初始化UI,但是不会做任何数据加载。等滑到该页,才会异步做数据加载并更新UI。

这里就实现类似微信那种效果,整个UI布局为:底部用PagerBottomTabStrip项目实现,上面是ViewPager,使用FragmentPagerAdapter。逻辑为:当用户滑到另一个界面,首先会显示正在加载,等数据加载完毕后(这里用睡眠1秒钟代替)显示正常界面。

ViewPager默认缓存左右相邻界面,为了避免不必要的重新数据加载(重复调用onCreateView()),因为有4个tab,因此将离线缓存的半径设置为3,即setOffscreenPageLimit(3)。

懒加载主要依赖Fragment的setUserVisibleHint(boolean isVisible)方法,当Fragment变为可见时,会调用etUserVisibleHint(true);当Fragment变为不可见时,会调用setUserVisibleHint(false),且该方法调用时机:

  • onAttach()之前,调用setUserVisibleHint(false)
  • onCreateView()之前,如果该界面为当前页,则调用setUserVisibleHint(true),否则调用setUserVisibleHint(false)
  • 界面变为可见时,调用setUserVisibleHint(true)
  • 界面变为不可见时,调用setUserVisibleHint(false)

懒加载Fragment的实现:

public class LazyFragment extends Fragment {

    private View mRootView;
    private boolean mIsInited;
    private boolean mIsPrepared;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mRootView = inflater.inflate(R.layout.fragment_lazy, container, false);
        mIsPrepared = true;
        lazyLoad();
        return mRootView;
    }

    public void lazyLoad() {
        if (getUserVisibleHint() && mIsPrepared && !mIsInited) {
            //异步初始化,在初始化后显示正常UI
            loadData();
        }
    }

    private void loadData() {
        new Thread() {
            public void run() {
                //1. 加载数据
                //2. 更新UI
                //3. mIsInited = true
            }
        }.start();
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
            lazyLoad();
        }
    }

    public static LazyFragment newInstance() {
        return new LazyFragment();
    }
}

注意点:

  • 在Fragment中有两个变量控制是否需要做数据加载:
    • mIsPrepared:表示UI是否准备好,因为数据加载后需要更新UI,如果UI还没有inflate,就不需要做数据加载,因为setUserVisibleHint()会在onCreateView()之前调用一次,如果此时调用,UI还没有inflate,因此不能加载数据。
    • mIsInited:表示是否已经做过数据加载,如果做过了就不需要做了。因为setUserVisibleHint(true)在界面可见时都会调用,如果滑到该界面做过数据加载后,滑走,再滑回来,还是会调用setUserVisibleHint(true),此时由于mIsInited=true,因此不会再做一遍数据加载。
  • lazyLoad():懒加载的核心类,在该方法中,只有界面可见(getUserVisibleHint()==true)、UI准备好(mIsPrepared==true)、过去没做过数据加载(mIsInited==false)时,才需要调loadData()做数据加载,数据加载做完后把mIsInited置为true。

布局XML主要分两个container,一个是初始显示的状态,即R.id.container_empty,当数据加载完成,就显示R.id.container:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:id="@+id/container_empty"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="正在加载"
            />

    </RelativeLayout>
    <RelativeLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"
        >
        ...
    </RelativeLayout>
</FrameLayout>

参考文献

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏androidBlog

ARouter 使用教程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/de...

1521
来自专栏肖蕾的博客

为APP添加一个登录刷新已打开UI机制

1055
来自专栏向治洪

android断点下载

断点下载往往用在大文件的下载过程中,如传统的迅雷下载用的就是断点下载技术,说起来原理比较简单:对文件进行分片,并对分片的文件进行标记,然后分片下载,下载完成后对...

23610
来自专栏Hellovass 的博客

动态生成分享图片

本文描述了如何实现该需求的思路,代码可能不通用,但是该思路应该可以解决很多类似的需求…

3133
来自专栏Android知识点总结

Android原生下载(下篇)多文件下载+多线程下载

1303
来自专栏cloudskyme

gwt之mvc4g

Mvc4g是一个简单的框架来实现的GWT应用程序的MVC模式。 主要思想 其主要思想是,以减轻开发人员的工作,以单独的视图从模型。该框架是一个XML文件,将允...

3276
来自专栏developerHaoz 的安卓之旅

Android Volley 源码解析(三),图片加载的实现

在上一篇文章中,我们一起深入探究了 Volley 的缓存机制,通过源码分析对缓存的工作原理进行了了解,这篇文章将带大家一起探究「Volley 图片加载的实现」,...

872
来自专栏Android-薛之涛

Android-Fragment

我们在创建Fragment的管理器的时候,会选择导入那个包下的FragmentManager.有app包下和v4包下的,这里我推荐用v4包的FragmentMa...

1403
来自专栏分享达人秀

日期选择器DatePicker和时间选择器TimePicker

在实际开发中,经常会遇见一些时间选择器、日期选择器、数字选择器等需求,那么从本期开始来学习Android中常用选择器,今天学习的是DatePicker和...

3075
来自专栏向治洪

android插件开发机制

插件机制实质上就是由主体程序定义接口,然后由插件去实现这些接口,以达到功能模块化。Android系统是基于Linux内核的,其安全机制也继承了Linux的特性...

2177

扫码关注云+社区