最近遇到比较奇怪的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. ML第6周学习小结

    本周收获 总结一下本周学习内容: 1.学习了<深入浅出Pandas>的第六章:Pandas分组聚合 6.1概述 6.2分组 6.3分组对象的操作 我的博客链接: Pandas 分组聚合 : ...

  2. 羿网通WT2100网络测试仪端口开关功能应用案例

    端口开关是羿网通WT2100具备的一项全局性的功能,使用客户端软件Packlark连接WT2100后无需进入具体功能即可使用.该功能是通过控制设备上的以太网开关实现快速.便捷地切换网口通断状态的目标, ...

  3. Code Forces 1367A Sorting Parts 题解

    (原题链接:CF传送门) 题目背景(我看不懂英文嘤嘤嘤) Sorting Parts You have an array a of length n. You can exactly once sel ...

  4. 内网 Ubuntu 20.04 搭建 docusaurus 项目(或前端项目)的环境(mobaxterm、tigervnc、nfs、node)

    内网 Ubuntu 20.04 搭建 docusaurus 项目(或前端项目)的环境 背景 内网开发机是 win7,只能安装 node 14 以下,而 spug 的文档项目采用的是 Facebook ...

  5. 【Java集合】ArrayDeque源码解读

    简介 双端队列是一种特殊的队列,它的两端都可以进出元素,故而得名双端队列. ArrayDeque是一种以循环数组方式实现的双端队列,它是非线程安全的. 它既可以作为队列也可以作为栈. 继承体系 Arr ...

  6. 重学ES系列之变量的作用范围

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. UiPath剪贴板操作的介绍和使用

    一.剪切板操作的介绍 模拟用户使用剪切板操作的一种行为: 例如使用设置剪切板(SettoClipboard),从剪切板获取(GetfromClipboard)的操作 二.剪切板相关操作在UiPath中 ...

  8. NC14301 K-th Number

    NC14301 K-th Number 题目 题目描述 Alice are given an array A[1..N] with N numbers. Now Alice want to build ...

  9. Oracle 用户密码中包括了“@”字符串的错误提示解决方法

    Oracle 用户密码设置了带有"@"符号,正常登陆总是无法登陆,提示无法解析的连接字符串错误 解决办法:1:修改密码:修改密码使密码中不包括@符号:2:增加转义即可,在密码前后增 ...

  10. HTML 超文本标记语言 (Hyper Text Markup Language)

    1.HTML是什么 HTML指的超文本标记语言(Hyper Text Markup Language),是一种用来描述网页的语言.超文本指的是除了可以包含文字之外,还可以包含图片.链接.音乐.视频.程 ...