首页 > 其他分享 >实现ViewPager懒加载的三种方法

实现ViewPager懒加载的三种方法

时间:2022-12-09 18:32:10浏览次数:65  
标签:fragment ViewPager private mCurTransaction 三种 position null 加载


在项目中ViewPager和Fragment接口框架已经是处处可见,但是在使用中,我们肯定不希望用户在当前页面时就在前后页面的数据,加入数据量很大,而用户又不愿意左右滑动浏览,那么这时候ViewPager中本来充满善意的预加载就有点令人不爽了。我们能做的就是屏蔽掉ViewPager的预加载机制。虽然ViewPager中提供的有

setOffscreenPageLimit()来控制其预加载的数目,但是当设置为0后我们发现其根本没效果,这个的最小值就是1,也就是你只能最少前后各预加载一页。那么,这时候就得另觅方法了。


以下三种方法是我在学习和项目中尝试过的,需求实现了,但各有千秋,可结合不同场景使用。因为打算慢慢养成写博客的习惯,就总结在此,也希望对他人有所借鉴。


方法一 

在Fragment可见时请求数据。此方案仍预加载了前后的页面,但是没有请求数据,只有进入到当前Framgent时才请求数据。

优点:实现了数据的懒加载

缺点:一次仍是三个Framgment对象,不是完全意义的懒加载

public class FragmentSample extends Fragment{

...

@Override

public void setUserVisibleHint(boolean isVisibleToUser) {

super.setUserVisibleHint(isVisibleToUser);

if (isVisibleToUser) {

requestData(); // 在此请求数据

}

}

...

}

方法二

直接修改ViewPager源码。通过查看ViewPager源码可知,控制其预加载的是一个常量

DEFAULT_OFFSCREEN_PAGES,其默认值为1,表示当前页面前后各预加载一个页面,在这里我们直接将其设置为0即可,即去掉预加载。但是,这样有一个问题,那就是在使用其他控件时需要传入ViewPager时,这个就不能用了。

优点:完全屏蔽掉了预加载

缺点:应用太受限制,比如使用ViewPagerIndicator时需要传入ViewPager对象,这时傻眼了。

// 注意,这是直接拷贝的ViewPager的源码,只修改了注释处的代码
public class LazyViewPager extends ViewGroup {
private static final String TAG = "LazyViewPager";
private static final boolean DEBUG = false;
private static final boolean USE_CACHE = false;
// 默认为1,即前后各预加载一个页面,设置为0去掉预加载
private static final int DEFAULT_OFFSCREEN_PAGES = 0;
private static final int MAX_SETTLE_DURATION = 600; // ms
static class ItemInfo {
Object object;
int position;
boolean scrolling;
}
private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>() {
@Override
public int compare(ItemInfo lhs, ItemInfo rhs) {
return lhs.position - rhs.position;
}
};
............
}


方法三

直接继承ViewPager,结合PagerAdapter实现懒加载。该方案是我用到的最完善的方法,完全的懒加载,每次只会建立一个Fragment对象。

优点:完全屏蔽预加载

缺点:稍微复杂,但是人家已经造好的轮子,直接用吧,很简洁

开源库:​​https://github.com/lianghanzhen/LazyViewPager​

这个库就4个类,作者通过继承ViewPager(保证其普适性)、自定义ViewPagerAdapter和 LazyFragmentPagerAdapter以及设置懒加载的标记接口,很好的实现了懒加载。感谢作者。

在此贴出关键代码,有兴趣的同学可以学习下。

LazyViewPager:

public class LazyViewPager extends ViewPager {
private static final float DEFAULT_OFFSET = 0.5f;
private LazyPagerAdapter mLazyPagerAdapter;
private float mInitLazyItemOffset = DEFAULT_OFFSET;
public LazyViewPager(Context context) {
super(context);
}
public LazyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LazyViewPager);
setInitLazyItemOffset(a.getFloat(R.styleable.LazyViewPager_init_lazy_item_offset, DEFAULT_OFFSET));
a.recycle();
}
/**
* change the initLazyItemOffset
* @param initLazyItemOffset set mInitLazyItemOffset if {@code 0 < initLazyItemOffset <= 1}
*/
public void setInitLazyItemOffset(float initLazyItemOffset) {
if (initLazyItemOffset > 0 && initLazyItemOffset <= 1) {
mInitLazyItemOffset = initLazyItemOffset;
}
}
@Override
public void setAdapter(PagerAdapter adapter) {
super.setAdapter(adapter);
mLazyPagerAdapter = adapter != null && adapter instanceof LazyPagerAdapter ? (LazyPagerAdapter) adapter : null;
}
@Override
protected void onPageScrolled(int position, float offset, int offsetPixels) {
if (mLazyPagerAdapter != null) {
if (getCurrentItem() == position) {
int lazyPosition = position + 1;
if (offset >= mInitLazyItemOffset && mLazyPagerAdapter.isLazyItem(lazyPosition)) {
mLazyPagerAdapter.startUpdate(this);
mLazyPagerAdapter.addLazyItem(this, lazyPosition);
mLazyPagerAdapter.finishUpdate(this);
}
} else if (getCurrentItem() > position) {
int lazyPosition = position;
if (1 - offset >= mInitLazyItemOffset && mLazyPagerAdapter.isLazyItem(lazyPosition)) {
mLazyPagerAdapter.startUpdate(this);
mLazyPagerAdapter.addLazyItem(this, lazyPosition);
mLazyPagerAdapter.finishUpdate(this);
}
}
}
super.onPageScrolled(position, offset, offsetPixels);
}
}

public abstract class LazyFragmentPagerAdapter extends LazyPagerAdapter<Fragment> {
private static final String TAG = "LazyFragmentPagerAdapter";
private static final boolean DEBUG = false;
private final FragmentManager mFragmentManager;
private FragmentTransaction mCurTransaction = null;
public LazyFragmentPagerAdapter(FragmentManager fm) {
mFragmentManager = fm;
}
@Override
public void startUpdate(ViewGroup container) {
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG)
Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(container, position);
if (fragment instanceof Laziable) {
mLazyItems.put(position, fragment);
} else {
mCurTransaction.add(container.getId(), fragment, name);
}
}
if (fragment != getCurrentItem()) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG)
Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object + " v=" + ((Fragment) object).getView());
final long itemId = getItemId(position);
String name = makeFragmentName(container.getId(), itemId);
if (mFragmentManager.findFragmentByTag(name) == null) {
mCurTransaction.detach((Fragment) object);
} else {
mLazyItems.remove(position);
}
}
@Override
public Fragment addLazyItem(ViewGroup container, int position) {
Fragment fragment = mLazyItems.get(position);
if (fragment == null)
return null;
final long itemId = getItemId(position);
String name = makeFragmentName(container.getId(), itemId);
if (mFragmentManager.findFragmentByTag(name) == null) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
mCurTransaction.add(container.getId(), fragment, name);
mLazyItems.remove(position);
}
return fragment;
}
@Override
public void finishUpdate(ViewGroup container) {
if (mCurTransaction != null) {
mCurTransaction.commitAllowingStateLoss();
mCurTransaction = null;
mFragmentManager.executePendingTransactions();
}
}
@Override
public boolean isViewFromObject(View view, Object object) {
return ((Fragment) object).getView() == view;
}
public long getItemId(int position) {
return position;
}
private static String makeFragmentName(int viewId, long id) {
return "android:switcher:" + viewId + ":" + id;
}
/**
* mark the fragment can be added lazily
*/
public interface Laziable {
}
}

最后提醒一下:填充LazyViewPager的Fragment一定要实现接口LazyFragmentPagerAdapter.Laziable。

标签:fragment,ViewPager,private,mCurTransaction,三种,position,null,加载
From: https://blog.51cto.com/u_15907753/5926364

相关文章

  • 使用过滤器预加载数据
    核心用法引入其它页面<jsp:includepage="head.jsp"></jsp:include>过滤器处理数据packagefilter;importjavax.servlet.*;importjavax.servlet.annotation.WebFilter;imp......
  • 懒加载
    懒加载:分页获取后台数据。懒加载本身好实现,在页面下方放一个“加载中”控件,使用原生的intersectionObserver(https://developer.mozilla.org/zh-CN/docs/Web/API/Inters......
  • android webView 文字、图片分别加载。乱码问题
     1.加载url前,设置图片阻塞1.webSettings.setBlockNetworkImage(true);2.加载完毕后,关闭图片阻塞1.publicvoidonPageFinished(WebViewview,Stringurl){2.......
  • FusionCharts Free-使用JS加载-flash图表
    使用JS加载 这个JS类文件就在FusionChartsFree>JSClass文件夹下,我们把它拷贝到c:FusionChartsFusionCharts下面。现在,我们把原来的Chart.html复制一份,命名为JSCh......
  • 数据库,部分函数依赖,传递函数依赖,完全函数依赖,三种范式的区别
    要讲清楚范式,就先讲讲几个名词的含义吧:部分函数依赖:设X,Y是关系R的两个属性集合,存在X→Y,若X’是X的真子集,存在X’→Y,则称Y部分函数依赖于X。举个例子:学生基本信息表R中(学号,......
  • jquery scroll 滚动加载列表 获取腾讯云图片像素信息
    jqueryscroll滚动加载列表获取腾讯云图片像素信息​​场景描述​​​​问题处理​​​​其他问题处理​​场景描述bootstarp列表加载图片时需要同时获取图片的像素(宽and......
  • 01jQuery之获取和引用jQ、页面加载事件绑定、基本选择器、过滤选择器
    下载:进入​​jQuery官网​​,进行下载,其中jQuery库分开发版和发布版引用jQ:<scriptsrc="js/jquery-1.12.4.js"type="text/javascript"></script>页面加载事件绑定:其中jq......
  • Linux系统常见的三种设备分类!
    Linux系统中设备主要分为哪几类?在Linux中,设备主要分为三种,分别是:块设备、字符设备和网络设备,接下来通过这篇文章详细介绍一下。Linux系统中的设备可以分为字符设备......
  • ArcGIS插件 - 易至天工影像加载插件
    众所周知,谷歌地图由于其分辨率高、更新速度快,且一直免费,受到行业内外各种人士的青睐,也正因如此,有人利用,有人嫉妒,导致它在国内市场无法再继续下去了。各大相关软件产商也主......
  • 三种过渡到IPv6的隧道模式
    隧道模式直接利用现有IPv4网络实现与IPv6网络的通信。1、6PE在核心网络是IPv4网络的情况下,如果要构建一个IPv6网络,可以通过在支持IPv6协议的边界路由器之间建立IPv6隧道,由这......