本文转载自点击打开链接

1.目标

主界面要求水平移动翻页效果,每次只能翻一页,可以翻无数页。

2.实现思路

针对“每次只能翻一页”这个要求,简单使用SDK的话只有用ViewPager。ViewPager的PageAdapter是没有实现RecyclerView的ViewHolder.itemView回收机制的。即使是子类FragmentStatePagerAdapter,也只是保存状态后销毁Fragment,Fragment本身是在不断地创建和销毁,没有重复利用。

正确地使用PageAdapter,必须先理解Object instantiateItem (ViewGroup container, int position)函数中返回的Object的意义。如果View能重复利用,则表明它仅用于展示数据,没有业务逻辑。数据的部分,我们通常用Model表示。instantiateItem函数的返回值Object,正是要求返回在position位置的Model数据对象,与实现这个函数时创建的View形成映射关系。

3.自定义PageAdapter

直接在代码注释中讲解

private class ViewPageAdapter extends PagerAdapter {// 用List保存本来要销毁的View,需要的时候再取出来private List<ItemView> mViewRecycler = new LinkedList<>();// 用Map保存Model Object(这里是OnePiece)和View的映射关系private Map<OnePiece, ItemView> mOnePieceItemViewMap = new HashMap<>();@Overridepublic int getCount() {// Model保存着OnePiece的对象数组return mPieceModel.pieces.size();}@Overridepublic boolean isViewFromObject(View view, Object object) {// 如果不需要回收利用View,都是用`return view == object`实现的,// 与此对应`instantiateItem()`返回View,// `destroyItem()`要销毁View。OnePiece onePiece = (OnePiece) object;return view == mOnePieceItemViewMap.get(onePiece);}@Overridepublic Object instantiateItem (ViewGroup container, int position) {ItemView itemView;// 这个if else是实现回收利用的关键处之一。如果有缓存则取缓存,// 没有则创建对象if (mViewRecycler.size() > 0) {itemView = mViewRecycler.remove(0);} else {itemView = (ItemView) LayoutInflater.from(MainActivity.this).inflate(R.layout.item_view, container, false);}// container实际是ViewPager对象。从这个函数的实现看,// ViewPager并不知道对它add的View是做什么用的,所以// 需要`isViewFromObject()`函数来询问这个View是否有// 意义(是ItemView),如果是,后面会对它做正确layoutcontainer.addView(itemView);OnePiece onePiece = mPieceModel.pieces.get(position);// 这里是itemView根据Model object来重新设置界面元素的时机。itemView.setOnePiece(onePiece);mOnePieceItemViewMap.put(onePiece, itemView);// 如果不需要回收利用View,这里的实现是`return itemView`。// 要回收,就要建立Model object和View的映射关系,因此// 这里返回Model objectreturn onePiece;}@Overridepublic void destroyItem (ViewGroup container, int position, Object object) {OnePiece onePiece = (OnePiece) object;ItemView itemView = mOnePieceItemViewMap.remove(onePiece);// 必须自行remove itemViewcontainer.removeView(itemView);// itemView要被回收放入缓存了,这里提供一个时机做清理。itemView.reset();// 实现回收的关键处,把itemView保存到List里。而不是任由GC销毁。mViewRecycler.add(itemView);}// 必须重写此函数。super固定地`return POSITION_UNCHANGED`,// 这就会导致`notifyDataSetChanged()`没有效果,因为它的意义// 是说这个Model object的位置没变化,自然不需要刷新。@Overridepublic int getItemPosition(Object object) {OnePiece onePiece = (OnePiece) object;if (mPieceModel.pieces.contains(onePiece)) {return mPieceModel.pieces.indexOf(onePiece);} else {// 返回POSITION_NONE说明这个model object已经被废弃了,// 接下来就会由`destroyItem()`回调来销毁它对应的View。return POSITION_NONE;}}
}

界面结构:5个按钮,分别是增、删、重置Model object。下面是ViewPager,按完按钮滚动区域会有变化。每一页有三个TextView,其中最上面的是显示ItemView本身的引用信息,留意它的引用地址(如截图中的12f46ad2),会发现最多创建4个ItemView(缓存了左、右、当前,还有一个预备),再怎么滑都会重复利用。

截图: 

下面是贴些代码,可不看了:

OnePiece.java

public class OnePiece {public char letter;public int number;public OnePiece(char letter, int number) {this.letter = letter;this.number = number;}
}

item_view.xml

<com.example.liuhx.viewpagerdemo.ItemViewxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#ccc"android:orientation="vertical"android:paddingTop="40dp"android:paddingBottom="40dp"android:paddingLeft="20dp"android:paddingRight="20dp"><TextViewandroid:id="@+id/this_info"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="reference info" /><TextViewandroid:id="@+id/text1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="sample1" /><TextViewandroid:id="@+id/text2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="sample2" /></com.example.liuhx.viewpagerdemo.ItemView>

ItemView.java

public class ItemView extends LinearLayout {private TextView mTextView1;private TextView mTextView2;private OnePiece mOnePiece;public ItemView(Context context, AttributeSet attrs) {super(context, attrs);}public void setOnePiece(OnePiece onePiece) {mOnePiece = onePiece;mTextView1.setText(String.valueOf(onePiece.letter));mTextView2.setText(String.valueOf(onePiece.number));}public void reset() {// Release resource here: network connection, database cursor, ...mOnePiece = null;}@Overridepublic void onFinishInflate() {// To differentiate View objects.((TextView) findViewById(R.id.this_info)).setText(this.toString());mTextView1 = (TextView) findViewById(R.id.text1);mTextView2 = (TextView) findViewById(R.id.text2);}
}

PieceModel.java

public class PieceModel {public interface OnPiecesChangedListener {void onPiecesChanged();}public List<OnePiece> pieces = new LinkedList<>();private OnPiecesChangedListener mOnPiecesChangedListener;private char mLetterSeed = 'A';private int mNumberSeed = 0;public void setOnPiecesChangedListener(OnPiecesChangedListener listener) {mOnPiecesChangedListener = listener;}public void addPiece(boolean toTail) {OnePiece onePiece = new OnePiece(mLetterSeed, mNumberSeed++);if (toTail)pieces.add(onePiece);elsepieces.add(0, onePiece);mOnPiecesChangedListener.onPiecesChanged();}public void removePiece(boolean fromTail) {if (fromTail)pieces.remove(pieces.size() - 1);elsepieces.remove(0);mOnPiecesChangedListener.onPiecesChanged();}public void changePieces() {++mLetterSeed;mNumberSeed = 0;int size = pieces.size();pieces.clear();for (; mNumberSeed < size; ++mNumberSeed) {OnePiece onePiece = new OnePiece(mLetterSeed, mNumberSeed);pieces.add(onePiece);}mOnPiecesChangedListener.onPiecesChanged();}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.example.liuhx.viewpagerdemo.MainActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:id="@+id/add_head"android:text="add head"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:id="@+id/add_tail"android:text="add tail"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:id="@+id/remove_head"android:text="remove head"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:id="@+id/remove_tail"android:text="remove tail"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:id="@+id/change"android:text="change"/></LinearLayout><android.support.v4.view.ViewPagerandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/view_pager" />
</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {private ViewPager mViewPager;private ViewPageAdapter mViewPageAdapter;private PieceModel mPieceModel;private class ViewPageAdapter extends PagerAdapter {private List<ItemView> mViewRecycler = new LinkedList<>();private Map<OnePiece, ItemView> mOnePieceItemViewMap = new HashMap<>();@Overridepublic int getCount() {return mPieceModel.pieces.size();}@Overridepublic boolean isViewFromObject(View view, Object object) {OnePiece onePiece = (OnePiece) object;return view == mOnePieceItemViewMap.get(onePiece);}@Overridepublic Object instantiateItem (ViewGroup container, int position) {ItemView itemView;if (mViewRecycler.size() > 0) {itemView = mViewRecycler.remove(0);} else {itemView = (ItemView) LayoutInflater.from(MainActivity.this).inflate(R.layout.item_view, container, false);}container.addView(itemView);OnePiece onePiece = mPieceModel.pieces.get(position);itemView.setOnePiece(onePiece);mOnePieceItemViewMap.put(onePiece, itemView);return onePiece;}@Overridepublic void destroyItem (ViewGroup container, int position, Object object) {OnePiece onePiece = (OnePiece) object;ItemView itemView = mOnePieceItemViewMap.remove(onePiece);container.removeView(itemView);itemView.reset();mViewRecycler.add(itemView);}// Must override this method, or else notifyDataSetChanged() has no effect.@Overridepublic int getItemPosition(Object object) {OnePiece onePiece = (OnePiece) object;if (mPieceModel.pieces.contains(onePiece)) {return mPieceModel.pieces.indexOf(onePiece);} else {return POSITION_NONE;}}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mPieceModel = new PieceModel();mPieceModel.setOnPiecesChangedListener(new PieceModel.OnPiecesChangedListener() {@Overridepublic void onPiecesChanged() {mViewPageAdapter.notifyDataSetChanged();}});mViewPager = (ViewPager) findViewById(R.id.view_pager);mViewPageAdapter = new ViewPageAdapter();mViewPager.setAdapter(mViewPageAdapter);mViewPager.setOffscreenPageLimit(1);findViewById(R.id.add_head).setOnClickListener(this);findViewById(R.id.add_tail).setOnClickListener(this);findViewById(R.id.remove_head).setOnClickListener(this);findViewById(R.id.remove_tail).setOnClickListener(this);findViewById(R.id.change).setOnClickListener(this);}@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.add_head:mPieceModel.addPiece(false);break;case R.id.add_tail:mPieceModel.addPiece(true);break;case R.id.remove_head:if (mPieceModel.pieces.size() == 0) {Toast.makeText(this, "Please press ADD first", Toast.LENGTH_SHORT).show();} else {mPieceModel.removePiece(false);}break;case R.id.remove_tail:if (mPieceModel.pieces.size() == 0) {Toast.makeText(this, "Please press ADD first", Toast.LENGTH_SHORT).show();} else {mPieceModel.removePiece(true);}break;case R.id.change:if (mPieceModel.pieces.size() == 0) {Toast.makeText(this, "Please press ADD first", Toast.LENGTH_SHORT).show();} else {mPieceModel.changePieces();}break;default:break;}}
}

ViewPager实现Recycle机制和响应相关推荐

  1. ViewPager的缓存机制

    1.实现Viewpager的页面懒加载: 在某些情况下,例如使用ViewPager查看多张大图,此时多张图片不能一次性载入,只有在浏览该页面时才载入(或者预先载入下一页面)页面的具体内容. 2.可控V ...

  2. 碳交易机制下考虑需求响应的综合能源系统优化运行综合能源系统是实现“双碳”目标的有效途径

    碳交易机制下考虑需求响应的综合能源系统优化运行综合能源系统是实现"双碳"目标的有效途径,为进一步挖掘其需求侧可调节潜力对碳减排的作用,提出了一种碳交易机制下考虑需求响应的综合能源系 ...

  3. 友盟页面统计 - 关于Viewpager中的Fragment的生命周期

    Activity和Fragment各自理论上的生命周期 Activity的生命周期是较为经典也最清晰的,在此不表: Fragment从出现到广泛运用也有一段时间了,其标准生命周期也仅比Activity ...

  4. ​iOS的界面触摸事件处理机制,然后用一个实例来说明下应用场景.

    2019独角兽企业重金招聘Python工程师标准>>> 主要是记录下iOS的界面触摸事件处理机制,然后用一个实例来说明下应用场景. 一.处理机制 界面响应消息机制分两块,(1)首先在 ...

  5. ViewPager+Fragment懒加载

    原文链接:http://blog.csdn.net/linglongxin24/article/details/53205878 Android中ViewPager+Fragment取消(禁止)预加载 ...

  6. response获取响应内容_Project Reactor 深度解析 - 1. 响应式编程介绍,实现以及现有问题

    现在, Java 的各种基于 Reactor 模型的响应式编程库或者框架越来越多了,像是 RxJava,Project Reactor,Vert.x 等等等等.在 Java 9, Java 也引入了自 ...

  7. 【Android】Fragment懒加载和ViewPager的坑

    本篇文章已授权微信公众号 安卓巴士Android开发者门户 独家发布 效果 老规矩,先来看看效果 ANDROID和福利两个Fragment是设置的Fragment可见时加载数据,也就是懒加载.圆形的旋 ...

  8. NISP-信息安全事件与应急响应

    文章目录 NISP-信息安全事件与应急响应 1.信息安全事件 2.信息安全事件分类 3.信息安全事件分级三要素 信息系统重要程度 系统损失 社会影响 4.信息安全事件分级 5.信息安全应急响应 6.应 ...

  9. 阿里云开发板HaaS510响应UART串口指令

    摘要:开发物联网设备时,常用MCU+物联网模块的硬件结构,HaaS510就是一款非常好的物联网模块.本文与大家分享HaaS510在成功上云基础上,如何响应UART串口指令. 实验目的:通过haas51 ...

最新文章

  1. 大盘点|YOLO 系目标检测算法总览
  2. Oracle 11g 预定义账户和PLSQL工具、企业管理器的初步使用
  3. 区块链培训资料(特别是以太坊)
  4. postgreSQL源码分析——索引的建立与使用——GIN索引(2)
  5. border-box
  6. 《财产》评最受尊重公司:苹果第一谷歌第二
  7. php和python_c语言,python和c语言的主要区别
  8. Eclipse代码自动提示设置
  9. linux网络编程之:UDP数据包格式
  10. 计算机t恤,PS一分钟技巧!给T恤加个图案竟然这么简单
  11. WINDOWS 7 PRO X64 2015年9月增量补丁包微软官方下载地址
  12. 做uni-app时,遇到后台返回base64码,将base64码转为图片,但是图片没有显示出来的解决方法
  13. 世界5G大会 大兴机场 随记
  14. 【翻译】使用Sencha Ext JS创建美丽的图画(1)
  15. 什么是user agent(用户代理)
  16. CPU(AMD)2020.10购买推荐
  17. C语言(谭浩强版本,主讲人:小甲鱼)P1-P9
  18. Android内存优化(二)之Bitmap的内存申请与回收(Android N和O的对比)
  19. ACM技术栈(知识栈)
  20. 阿里云ACP ACE认证考试重要事项

热门文章

  1. 【人工智能】如何Finetune一个小网络到移动端(时空性能分析篇)
  2. 【人工智能】深度学习自动构图研究报告
  3. 两年,从月入4K到40K,从来不是努力工作,而是不断跳槽
  4. python原创第十四篇~判断,循环实战训练+答案
  5. python变量赋值方式_python变量和变量赋值的几种形式
  6. 华为第二批“十大军团”正式成立!
  7. 王者归来!iPhone 13热销立功 苹果重夺销量全球第一
  8. 《快乐大本营》升级改版 此举对芒果超媒整体收益并无太大影响
  9. 蔚来三元铁锂电池绕道超车
  10. 用户微信好友关系属于个人隐私吗?深圳南山法院说不属于...