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 条评论
登录 后参与评论

相关文章

来自专栏SAP最佳业务实践

SAP最佳业务实践:MM–采购合同(133)-3收货、开票

五、ME80RN 监控合同 如果要监控现有供应商合同,则需要执行该活动。 角色采购员 后勤-物料管理-采购-框架协议-报表-一般分析 1. 在常规评估屏幕...

4235
来自专栏小狼的世界

为什么选择Mapabc

目前网络上有众多的在线电子地图服务,诸如Mapabc、Google Maps、Yahoo Maps、Mapbar、Microsoft Virtual Earth...

671
来自专栏区块链入门

第八课 如何调试以太坊官网的智能合约众筹案例

【本文目标】 发布并执行通ETH官网的众筹合约代码。 【前置条件】 参考《第七课 技术小白如何在45分钟内发行通证(TOKEN)并上线交易》完成了Colo...

782
来自专栏FreeBuf

《绝地求生》辅助程序暗藏挖矿木马

0x1 概述 数字货币“挖矿”, 通俗讲就是猜数字求解,猜对即可获得数字货币奖励。目前已知的数字货币约有100多种,包括比特币、莱卡币、门罗币等常见类型,并且近...

2947
来自专栏SAP最佳业务实践

从SAP最佳业务实践看企业管理(156)-WM-624包括分配运行的仓库管理

WM 624包括分配运行的仓库管理 本流程表述了在分销中心针对货物的不带HUM的仓库管理,包含以下功能: 补货 创建转储要求 创建转储要求的转储单 确认转储单 ...

2827
来自专栏腾讯Bugly的专栏

Android 5.0 来了,你的应用准备好了么?

在快速发展的移动互联网时代,新技术,新概念层出不穷,即便身处移动互联网核心的移动开发者也常有落伍的感觉,我是四眼哥,在繁忙的工作间隙,抽时间用“四只眼”帮大家盯...

3337
来自专栏SAP最佳业务实践

想学FM系列(7)-SAP FM模块:主数据(5)-基金计划程序

3.1.4 基金计划程序 基金计划程序是可选账户分配要素,可以用它来进行跨公司、跨年度的框架内预算控制,比如一个大型项目。它同其他账户分配要素不同,它可以直接进...

2748
来自专栏FreeBuf

揭秘比木马挖矿还要“暴利”的网络偷窃行为

说起木马挖矿,那些利用永恒之蓝和其他漏洞挖矿的方式,对于我说的这种显得就不那么暴利了。以一种合理合法的方式运行的他人电脑上,并且不告诉用户,光天化日之下夺走别人...

3545
来自专栏大数据挖掘DT机器学习

R&Python玩家诉求词云分析

作者:Fish http://www.gamedas.com 一、数据爬虫 在实际工作中,数据的来源不能局限于自家的数据库或者成型的后台,在做某些市场分析或是竞...

3216
来自专栏jouypub

Hive之行转列/列转行

场景:在hive表中,一个用户会有多个人群标签,List格式(逗号分隔如要转成List),有时我们需要统计一个人群标签下有少用户,这是就需要使用行转列了

1234

扫码关注云+社区