ViewPager防止Fragment销毁以及取消Fragment的预加载
存在的问题
1. 默认情况下,ViewPager会根据setOffscreenPageLimit()方法设置的大小,自动预加载
2. 还是根据setOffscreenPageLimit()方法设置的大小,会去销毁fragment视图
下面的图说明情况
滑动fragment1,此时会预加载fragment2,滑动到fragment2会预加载fragment3,但是滑动到fragment3,此时会调用fragment1的destroyview方法,销毁视图。当重新滑动到fragment1才会重新调用fragment1的oncreateview方法。注意此时并不会销毁实例,不会调用ondestroy方法
这样就存在两个问题
1.pagerview频繁切换,导致fragment1.fragment3在频繁的调用destroyview和oncreateview方法,重新创建视图。这样也浪费了大量的资源,用户体验不佳,虽然内存消耗比较低
2.因为切换到fragment1的时候,同时预加载了fragment2,如果此时fragment2也有大量的耗时网络请求要做,如果应用对启动反应速度比较敏感,所以此时做了多余的工作。能否把这些耗时的工作延迟加载,也是个问题
解决方案
1. 防止频繁的销毁视图,setOffscreenPageLimit(2)/或者重写PagerAdaper的destroyItem方法为空即可
setOffscreenPageLimit(2)
//Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state.Pages beyond this limit will be recreated from the adapter when needed.You should keep this limit low, especially if your pages have complex layouts. This setting defaults to 1.
大概意思就是说:
设置当前page左右两侧应该被保持的page数量,超过这个限制,page会被销毁重建(只是销毁视图),onDestroy-onCreateView,但不会执行onDestroy。尽量维持这个值小,特别是有复杂布局的时候,因为如果这个值很大,就会占用很多内存,如果只有3-4page的话,可以全部保持active,可以保持page切换的顺滑
这下很好理解了,默认情况下是1,所以当前fragment左右两侧,就会被保持1页pager,所以上述切换到fragment2并不会销毁任何视图,但是到fragment1,3会。这里注意这个值,是左右两侧能够维持的page,所以如果setOffscreenPageLimit(2),那么就不会频繁的销毁了
destroyItem()
//super.destroyItem(Container, position, object); 注释掉调用父类方法即可
2. 取消预加载,可以fragment的setUserVisibleHint实现,具体实现参考代码示例
setUserVisibleHint
//Set a hint to the system about whether this fragment's UI is currently visible to the user. This hint defaults to true and is persistent across fragment instance state save and restore.An app may set this to false to indicate that the fragment's UI is scrolled out of visibility or is otherwise not directly visible to the user. This may be used by the system to prioritize operations such as fragment lifecycle updates or loader ordering behavior.
大概意思就是:fragment对用户可见,isVisibleToUser为true,不可见isVisibleToUser为false。对应于viewpager,当前pager,非当前pager
代码:
public abstract class BaseFragment extends Fragment {
/** Fragment当前状态是否可见 */
protected boolean isVisible;
//setUserVisibleHint adapter中的每个fragment切换的时候都会被调用,如果是切换到当前页,那么isVisibleToUser==true,否则为false
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser) {
isVisible = true;
onVisible();
} else {
isVisible = false;
onInvisible();
}
}
/**
* 可见
*/
protected void onVisible() {
lazyLoad();
}
/**
* 不可见
*/
protected void onInvisible() {
}
/**
* 延迟加载
* 子类必须重写此方法
*/
protected abstract void lazyLoad();
}
public class CustomListFragment extends BaseFragment {
private Context context;
private static final String FRAGMENT_INDEX = "fragment_index";
private final int FIRST_FRAGMENT = 0;
private final int SECOND_FRAGMENT = 1;
private final int THIRD_FRAGMENT = 2;
private TextView contentText;
private ProgressBar progressBar;
private int mCurIndex = -1;
/**
* 标志位,标志已经初始化完成
*/
private boolean isPrepared;
/**
* 是否已被加载过一次,第二次就不再去请求数据了
*/
private boolean mHasLoadedOnce;
/**
* 创建新实例
*
* @param index
* @return
*/
public static CustomListFragment newInstance(int index) {
Bundle bundle = new Bundle();
bundle.putInt(FRAGMENT_INDEX, index);
CustomListFragment fragment = new CustomListFragment();
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = getActivity();
Bundle bundle = getArguments();
if (bundle != null) {
mCurIndex = bundle.getInt(FRAGMENT_INDEX);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment, container, false);
contentText = (TextView) view.findViewById(R.id.content);
progressBar = (ProgressBar) view.findViewById(R.id.progressbar);
isPrepared = true;
lazyLoad();
return view;
}
@Override
protected void lazyLoad() {
if (!isPrepared || !isVisible || mHasLoadedOnce) {
return;
}
new AsyncTask<Void, Void, Boolean>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
progressBar.setVisibility(View.VISIBLE);
}
@Override
protected Boolean doInBackground(Void... params) {
try {
Thread.sleep(2000);
//在这里添加调用接口获取数据的代码
//doSomething()
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
@Override
protected void onPostExecute(Boolean isSuccess) {
if (isSuccess) {
// 加载成功
setView();
mHasLoadedOnce = true;
} else {
// 加载失败
}
progressBar.setVisibility(View.GONE);
}
}.execute();
}
private void setView() {
// 根据索引加载不同视图
switch (mCurIndex) {
case FIRST_FRAGMENT:
contentText.setText("第一个");
break;
case SECOND_FRAGMENT:
contentText.setText("第二个");
break;
case THIRD_FRAGMENT:
contentText.setText("第三个");
break;
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.d("LiaBin", "onDestroyView: curIndex=" + mCurIndex);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("LiaBin", "onDestroy: curIndex=" + mCurIndex);
}
}
ViewPager防止Fragment销毁以及取消Fragment的预加载的更多相关文章
- 防止ViewPager和Fragment结合使用时候的数据预加载
不知道你们使用ViewPager和Fragment结合的时候发现一个问题没,如果你的每个Fragment都需要请求网络数据,并且你在请求网络数据的时候会加入进度对话框的加载显示效果,当你显示第一个Fr ...
- Android中ViewPager+Fragment取消(禁止)预加载延迟加载(懒加载)问题解决方案
转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53205878本文出自[DylanAndroid的博客] Android中Vie ...
- ViewPager+Fragment取消预加载(延迟加载)(转)
原文:http://www.2cto.com/kf/201501/368954.html 在项目中,都或多或少地使用的Tab布局,所以大都会用到ViewPager+Fragment,但是Fragmen ...
- ViewPager+Fragment取消预加载(延迟加载)
在项目中,都或多或少地使用的Tab布局,所以大都会用到ViewPager+Fragment,但是Fragment有个不好或者太好的地方.例如你在ViewPager中添加了三个Fragment,当加载V ...
- android Viewpager取消预加载及Fragment方法的学习
1.在使用ViewPager嵌套Fragment的时候,由于VIewPager的几个Adapter的设置来说,都会有一定的预加载.通过设置setOffscreenPageLimit(int numbe ...
- viewpager和fragment预加载的解决
在使用Viewpager和fragment处理中会出现预加载的问题,最近看别人的代码,终于找到了一个很好的处理方法 能有效的解决预加载的问题,在fragment都继承一个重写setUserVisibl ...
- 巧力避免ViewPager的预加载数据,Tablayout+Fragment+viewPager
问题描述 最近在进行一个项目的开发,其中使用到了Tablayout+Fragment+viewPager来搭建一个基本的框架,从而出现了设置数据适配器的时候,item的位置错乱问题.我打印log日志的 ...
- Fragment禁止预加载
项目中经常会用到ViewPager+Fragment组合,然而,有一个很让人头疼的问题就是,去加载数据的时候由于ViewPager的内部机制所限制,所以它会默认至少预加载一个. 1.既然说是ViewP ...
- Fragment懒加载预加载
1. 预加载viewpager.setOffscreenPageLimit(2);,默认是预加载1,可以结合懒加载使用. 如果希望进入viewpager,Fragment只加载一次,再次滑动不需加载( ...
随机推荐
- 京东架构师的showtime京东个性化推荐系统实战
推荐系统核心任务是排序,从线上服务角度看,就是将数据从给定集合中数据选择出来,选出后根据一定规则策略方法进行排序. 线上服务要根据一定规则进行架构设计,架构设计是什么?每一次权衡取舍都是设计,设计需要 ...
- ABP实践(3)-ASP.NET Core 2.x版本(从创建实体到输出api)简单实现商品列表及增删改
项目基于前两篇文章. 本章创建一个简单版的商品管理后台api,用到EF Core用code fist迁移数据创建数据库. 创建Goods实体 在领域层xxx.Core项目[新建文件夹Goods;文件夹 ...
- 【OSX】多个JDK共存时选择要使用的JDK版本
10.5以后的$JAVA_HOME没有被在.bash_profile中设置的话会被默认设置为 /usr/libexec/java_home. 如果一台mac里面安装了多个JDK, 可以通过/usr/l ...
- (原创)UML要点总结
今天我们总结要点: 我们就从这张图慢慢讲. 一.类图部分 基础: 类图→长方形表示.类名在最上栏,下面是数据,第三栏是方法.其存在两种关系:关联和泛化 属性: 全形: 可见性 名:类型 重 ...
- 从零开始学 Web 之 CSS3(六)动画animation,Web字体
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
- nginx介绍(三) - 虚拟主机
前言 前面提到过, 由nginx来分发请求到tomcat中, 那么怎么来区分这些tomcat呢? 我们一般访问网站的时候, 是不是可以使用 ip : port (127.0.0.1:8080)的方式来 ...
- k8s全栈监控之metrics-server和prometheus
一.概述 使用metric-server收集数据给k8s集群内使用,如kubectl,hpa,scheduler等 使用prometheus-operator部署prometheus,存储监控数据 使 ...
- python redis模块详解
前言 现在越来越觉得知识的沉淀尤为重要,最近打算慢慢的把一些知识点做个记录,如果长期不用生疏了也可以快速回顾.下面我会依次介绍在python中常用组件redis,rabbitmq,mongodb,E ...
- 完整的一次 HTTP 请求响应过程(二)
上篇文章 我们完整的描述了计算机五层模型中的『应用层』和『运输层』,阐述了较为复杂的 TCP 协议的相关原理,相信大家一定也有所收获,那么本篇将继续五层模型的学习. 网络层 『网络层』其实解决的就是一 ...
- spring-boot-2.0.3启动源码篇 - 阶段总结
前言 开心一刻 朋友喜欢去按摩,第一次推门进来的是一个学生美眉,感觉还不错:后来经常去,有时是护士,有时是空姐,有时候是教师.昨天晚上推门进去的是一个女警察,长得贼好看,身材也很好,朋友嗷的一声就扑上 ...