深入分析FragmentPagerAdapter和FragmentStatePagerAdapter
最近遇到比较奇怪的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的更多相关文章
- 转载---ViewPager,PagerAdapter,FragmentPagerAdapter和FragmentStatePagerAdapter的分析对比
转载:http://blog.csdn.net/dreamzml/article/details/9951577 ViewPager ViewPager 如其名所述,是负责翻页的一个 View.准确说 ...
- FragmentPagerAdapter与FragmentStatePagerAdapter区别
在一个 Android 应用中,我使用 FragmentPagerAdapter 来处理多 Fragment 页面的横向滑动.不过我碰到了一个问题,即当 Fragment 对应的数据集发生改变时,我希 ...
- 109、FragmentPagerAdapter与FragmentStatePagerAdapter区别
x 在一个 Android 应用中,我使用 FragmentPagerAdapter 来处理多 Fragment 页面的横向滑动.不过我碰到了一个问题,即当 Fragment 对应的数据集发生改变时, ...
- FragmentPagerAdapter与FragmentStatePagerAdapter差异
平常使用的FragmentPagerAdapter和FragmentStatePagerAdapter来自android.support.v4.app包用来构建ViewPager. FragmentP ...
- FragmentPagerAdapter 与 FragmentStatePagerAdapter的区别。通过验证证明的。
在一个 Android 应用中,我使用 FragmentPagerAdapter 来处理多 Fragment 页面的横向滑动.不过我碰到了一个问题,即当 Fragment 对应的数据集发生改变时,我希 ...
- FragmentPagerAdapter和FragmentStatePagerAdapter的差别
ViewPager同意用户通过左右滑动显示不同页面的数据.而这些页面须要PagerAdapter管理. 经常使用的有FragmentPagerAdapter和FragmentStatePagerAda ...
- [转][Android]FragmentPagerAdapter与FragmentStatePagerAdapter使用详解与区别
原文链接:http://blog.csdn.net/zhaokaiqiang1992 FragmentPagerAdapter是android-support-v4支持包里面出现的一个新的适配器,继承 ...
- 【Android界面实现】FragmentPagerAdapter与FragmentStatePagerAdapter使用详解与区别
转载请注明出处: http://blog.csdn.net/zhaokaiqiang1992 FragmentPagerAdapter是android-support-v4支持包里面出现的一个新的适配 ...
- Android FragmentPagerAdapter和FragmentStatePagerAdapter的区别
FragmentPagerAdapter官方解释: This version of the pager is best for use when there are a handful of typi ...
随机推荐
- 16岁男生信息竞赛成瘾心理出现问题 妈妈:他竟说要AK我
16岁男生信息竞赛成瘾心理出现问题 -- 妈妈:他竟说要AK我 "我儿子最近快走火入魔了,医生,你救救他吧."40出头的林女士拉着儿子走进江苏省人民医院临床心理科.近几年,信息竞赛 ...
- React简单教程-6-单元测试
前言 我想大部分人的前端测试,都是运行项目,直接在浏览器上操作,看看功能正不正常.虽然明明有测试库可以使用,但是因为"要快"的原因,让好好做测试变成了一件影响效率的事. 因为这种无 ...
- BitBlt()函数实现带数字百分比进度条控件、静态文本(STATIC)控件实现的位图进度条、自定义进度条控件实现七彩虹颜色带数字百分比
Windows API BitBlt()函数实现带数字百分比进度条控件. 有两个例子:一用定时器实现,二用多线程实现. 带有详细注解. 此例是本人原创,绝对是网上稀缺资源(本源码用Windows AP ...
- SpringCloud微服务实战——搭建企业级开发框架(四十一):扩展JustAuth+SpringSecurity+Vue实现多租户系统微信扫码、钉钉扫码等第三方登录
前面我们详细介绍了SSO.OAuth2的定义和实现原理,也举例说明了如何在微服务框架中使用spring-security-oauth2实现单点登录授权服务器和单点登录客户端.目前很多平台都提供了单 ...
- SpringBoot之:SpringBoot中使用HATEOAS
目录 简介 我们的目标 构建Entity和Repository 构建HATEOAS相关的RepresentationModel 构建Controller HATEOAS的意义 总结 简介 HATEOA ...
- 华为AppLinking中统一链接的创建和使用
运营的同学近期在准备海外做一波线下投放,涉及到海外的Google Play,iOS设备的App Store,以及华为渠道的AppGallery. 其中运营希望我们能够将三个平台的下载整合到一个链接 ...
- SAP 实例 13 Random Grouping with LOOP
REPORT demo_loop_group_by_random. CLASS demo DEFINITION. PUBLIC SECTION. CLASS-METHODS: main, class_ ...
- ansible变量引用
1. 在/etc/ansible/hosts默认文件中定义变量 [test] 192.168.163.130 #[test:vars] #key=ansible 或者 192.168.163.130 ...
- 深入解析kubernetes中的选举机制
Overview 在 Kubernetes的 kube-controller-manager , kube-scheduler, 以及使用 Operator 的底层实现 controller-rumt ...
- Linux安装fastdfs集群部署
过程问题: make: gcc:命令未找到 解决: yum -y install gcc 一.环境和版本: Linux环境:CentOS 7.6 libfastcommon版本:1.0.39 Fast ...