最近遇到比较奇怪的bug,TableLayout+ViewPager实现点击顶部tab切换viewpager视图。但是在Viewpager设置dapter时,最开始设置的是FragmentPagerAdapter,会导致tab切换后FragmentPagerAdapter内的视图未刷新(与上一个tab内容重复或展示成空白,展示成空白一般出现在页面重启后不能完成刷新成功)。替换成FragmentStatePagerAdapter或者FragmentStateAdapter,便解决了这一问题。这其实是个比较常见的bug,网络上有很多推荐的解决方案。那么到底FragmentPagerAdapter、FragmentStateAdapter以及FragmentStatePagerAdapter有何具体的区别呢?在这篇文章中我将详细解答。

根据类图进行分析

FragmentPagerAdapter与FragmentPagerStateAdapter区别点:

一:二者在状态保存有差异:FragmentPagerAdapter并未实现saveState()、restoreState()
public class FragmentPagerAdapter{
// ......
public static final int POSITION_UNCHANGED = -1;
public static final int POSITION_NONE = -2; public Parcelable saveState() {
return null;
} public void restoreState(Parcelable state, ClassLoader loader) { }
}

而FragmentPagerStateAdapter则实现了saveState()、restoreState()这俩方法:

 public Parcelable saveState() {
Bundle state = null;
if (mSavedState.size() > 0) {
state = new Bundle();
Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
mSavedState.toArray(fss);
state.putParcelableArray("states", fss);
}
for (int i=0; i<mFragments.size(); i++) {
Fragment f = mFragments.get(i);
if (f != null && f.isAdded()) {
if (state == null) {
state = new Bundle();
}
String key = "f" + i;
mFragmentManager.putFragment(state, key, f);
}
}
return state;
} @Override
public void restoreState(Parcelable state, ClassLoader loader) {
if (state != null) {
Bundle bundle = (Bundle)state;
bundle.setClassLoader(loader);
Parcelable[] fss = bundle.getParcelableArray("states");
mSavedState.clear();
mFragments.clear();
if (fss != null) {
for (int i=0; i<fss.length; i++) {
mSavedState.add((Fragment.SavedState)fss[i]);
}
}
Iterable<String> keys = bundle.keySet();
for (String key: keys) {
if (key.startsWith("f")) {
int index = Integer.parseInt(key.substring(1));
Fragment f = mFragmentManager.getFragment(bundle, key);
if (f != null) {
while (mFragments.size() <= index) {
mFragments.add(null);
}
f.setMenuVisibility(false);
mFragments.set(index, f);
} else {
Log.w(TAG, "Bad fragment at key " + key);
}
}
}
}
}

FragmentStatePagerAdapter对Fragment的状态进行了保存

二:二者在视图管理方法差异:

FragmentStatePagerAdapter是整个Fragment对象的移除和重建

 public Object instantiateItem(ViewGroup container, int position) {
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
return f;
}
} if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
} // 实例化fragment(交给我们实现的getItem方法)
Fragment fragment = getItem(position); if (mSavedState.size() > position) {
Fragment.SavedState fss = mSavedState.get(position);
if (fss != null) {
fragment.setInitialSavedState(fss);
}
}
// 如果缓存 <= ViewPager传入的position,说明当前位置还未存入缓存.
while (mFragments.size() <= position) {
// 先占个坑
mFragments.add(null);
}
fragment.setUserVisibleHint(false);
// 填坑
mFragments.set(position, fragment);
// 填充视图
mCurTransaction.add(container.getId(), fragment);
return fragment;
} @Override
public void destroyItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object; if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
// 从缓存中移除
mFragments.set(position, null);
// 从FragmentManager中移除
mCurTransaction.remove(fragment);
}

FragmentPagerAdapter是视图的attach和detach,不会对整个fragment进行完全的添加和删除操作。

因此,可见二者在使用场景上不同,如果页面较少,仍旧希望能够将生成的Fragment保存在内存中,在需要显示的时候直接调用。而不要产生生成、销毁对象的额外开销。这样效率最高。这种情况下,选中FragmentPagerAdapter更合适。
对于在使用FragmentPagerAdapter出现白屏或者刷新不了的bug,除了替换成FragmentStatePagerAdapter,还需要重载getItem()和instantiateItem()对象。

对于getItemPosition()方法,两个累的区别是:FragmentStatePagerAdapter会在因POSITION_NONE触发调用的destroyItem中真正的释放资源,重新建立一个新的Fragment;而FragmentPagerAdapter仅仅会在destoryItem()中detach这个Fragment,在instantiateItem()时会使用旧的Fragment,并触发attach,并没有触发资源及重建的过程。

深入分析FragmentPagerAdapter和FragmentStatePagerAdapter的更多相关文章

  1. 转载---ViewPager,PagerAdapter,FragmentPagerAdapter和FragmentStatePagerAdapter的分析对比

    转载:http://blog.csdn.net/dreamzml/article/details/9951577 ViewPager ViewPager 如其名所述,是负责翻页的一个 View.准确说 ...

  2. FragmentPagerAdapter与FragmentStatePagerAdapter区别

    在一个 Android 应用中,我使用 FragmentPagerAdapter 来处理多 Fragment 页面的横向滑动.不过我碰到了一个问题,即当 Fragment 对应的数据集发生改变时,我希 ...

  3. 109、FragmentPagerAdapter与FragmentStatePagerAdapter区别

    x 在一个 Android 应用中,我使用 FragmentPagerAdapter 来处理多 Fragment 页面的横向滑动.不过我碰到了一个问题,即当 Fragment 对应的数据集发生改变时, ...

  4. FragmentPagerAdapter与FragmentStatePagerAdapter差异

    平常使用的FragmentPagerAdapter和FragmentStatePagerAdapter来自android.support.v4.app包用来构建ViewPager. FragmentP ...

  5. FragmentPagerAdapter 与 FragmentStatePagerAdapter的区别。通过验证证明的。

    在一个 Android 应用中,我使用 FragmentPagerAdapter 来处理多 Fragment 页面的横向滑动.不过我碰到了一个问题,即当 Fragment 对应的数据集发生改变时,我希 ...

  6. FragmentPagerAdapter和FragmentStatePagerAdapter的差别

    ViewPager同意用户通过左右滑动显示不同页面的数据.而这些页面须要PagerAdapter管理. 经常使用的有FragmentPagerAdapter和FragmentStatePagerAda ...

  7. [转][Android]FragmentPagerAdapter与FragmentStatePagerAdapter使用详解与区别

    原文链接:http://blog.csdn.net/zhaokaiqiang1992 FragmentPagerAdapter是android-support-v4支持包里面出现的一个新的适配器,继承 ...

  8. 【Android界面实现】FragmentPagerAdapter与FragmentStatePagerAdapter使用详解与区别

    转载请注明出处: http://blog.csdn.net/zhaokaiqiang1992 FragmentPagerAdapter是android-support-v4支持包里面出现的一个新的适配 ...

  9. Android FragmentPagerAdapter和FragmentStatePagerAdapter的区别

    FragmentPagerAdapter官方解释: This version of the pager is best for use when there are a handful of typi ...

随机推荐

  1. CMU 15-445 数据库课程第四课文字版 - 存储2

    熟肉视频地址: CMU数据库管理系统课程[熟肉]4.数据库存储结构2(上) CMU数据库管理系统课程[熟肉]4.数据库存储结构2(下) 1. 面向日志的存储 上节课我们讲完了面向元组的存储,这节课从面 ...

  2. AGC007E Shik and Travel 解题报告

    AGC007E Shik and Travel 题目大意:\(n\) 个点的二叉树,每个点要么两个儿子,要么没有儿子,每条边有边权. 你从 \(1\) 号节点出发,走到一个叶子节点.然后每一天,你可以 ...

  3. 如何用HMS Core位置和地图服务实现附近地点路径规划功能

    日常出行中,路径规划是很重要的部分.用户想要去往某个地点,获取到该地点的所有路径,再根据预估出行时间自行选择合适的路线,极大方便出行.平时生活中也存在大量使用场景,在出行类App中,根据乘客的目的地可 ...

  4. 渗透测试之sql注入点查询

    一切教程在于安全防范,不在于攻击别人黑别人系统为目的 寻找sql注入点方法: 拿到网页后进行查找注入点: 1.通过单引号 ' ;    在 url 后面输入单引号进行回车(如果报错可能存在sql注入为 ...

  5. CentOS切换用户命令su or su+username

    1.打开终端,提示符为"$",表明该用户为普通用户,此时,直接输su,回车,输入root密码,回车,就可以切换到root用户下,此时的提示符变为"#". 注意, ...

  6. alertmanager集群莫名发送resolve消息的问题探究

    alertmanager集群莫名发送resolve消息的问题探究 术语 告警消息:指一条告警 告警恢复消息:指一条告警恢复 告警信息:指告警相关的内容,包括告警消息和告警恢复消息 问题描述 最近遇到了 ...

  7. 12.web基础与HTTP协议

    web基础与HTTP协议 目录 web基础与HTTP协议 web基础 域名概述 HTML概述 HTML基本标签 HTML语法规则 HTML文件结构 头标签中常用标签 内容标签中常用标签 静态网页与动态 ...

  8. 隐私计算FATE-模型训练

    一.说明 本文分享基于 Fate 自带的测试样例,进行 纵向逻辑回归 算法的模型训练,并且通过 FATE Board 可视化查看结果. 本文的内容为基于 <隐私计算FATE-概念与单机部署指南& ...

  9. STM32 移植 RT-Thread 标准版的 FinSH 组件

    一.移植准备 开发版STM32F10xC8T6 准备好移植RT-Thread的移植工程 没动手移植过RT-Thread的小伙伴,可以看RT-Thread移植到stm32 我这里是将控制台信息打印到串口 ...

  10. 《Stepwise Metric Promotion for Unsupervised Video Person Re-identification》 ICCV 2017

    Motivation: 这是ICCV 17年做无监督视频ReID的一篇文章.这篇文章简单来说基于两个Motivation. 在不同地方或者同一地方间隔较长时间得到的tracklet往往包含的人物是不同 ...