前言


上一篇的代码,也是基于这些封装的。

RV的封装,跟曾经的listView之类的封装,大同小异。

这里,从@devwiki 处,将代码搬过来。基本无改动

BaseHolder的优化


  1. 使ViewHolder仅仅用来缓存View。

  2. 加入SparseArray,使之来缓存View。

  3. 加入BaseHolder(View view)构造器,外部更方便控制View。

  4. 保留getContext()方法,方便获取Context对象。

  5. getView(resid)。简化itemView.findviewById()
/**
* from http://blog.devwiki.net/index.php/2016/07/17/Recycler-View-Adapter-ViewHolder-optimized.html
* 基础的ViewHolder</br>
* ViewHolder仅仅作View的缓存,不关心数据内容
* Created by DevWiki on 2016/5/17.
*/
public class BaseHolder extends RecyclerView.ViewHolder { private SparseArray<View> mViewArray; /**
* 构造ViewHolder (该方法涉及到parent,不经常使用)
* @param parent 父类容器
* @param resId 布局资源文件id
*/
public BaseHolder(ViewGroup parent, @LayoutRes int resId) {
super(LayoutInflater.from(parent.getContext()).inflate(resId, parent, false));
mViewArray = new SparseArray<>();
} /**
* 构造ViewHolder
* @param context
* @param resId 布局资源文件id
*/
public BaseHolder(Context context, @LayoutRes int resId) {
super(LayoutInflater.from(context).inflate(resId, null, false));
mViewArray = new SparseArray<>();
} /**
* 构建ViewHolder
* @param view 布局View
*/
public BaseHolder(View view) {
super(view);
mViewArray = new SparseArray<>();
} /**
* 获取布局中的View
* @param viewId view的Id
* @param <T> View的类型
* @return view
*/
public <T extends View> T getView(@IdRes int viewId){
View view = mViewArray.get(viewId);
if (view == null) {
view = itemView.findViewById(viewId);
mViewArray.put(viewId, view);
}
return (T) view;
} /**
* 获取Context实例
* @return context
*/
public Context getContext() {
return itemView.getContext();
}
}

Adapter部分的优化


Adapter拆分为两个抽象类:AbsAdapter与BaseAdapter,当中:

AbsAdapter:封装了和ViewHolder和HeaderView。FooterView相关的方法。

BaseAdapter:继承AbsAdapter。封装了数据相关的方法。

各自聚焦于不同的方面,方面日后扩展。

AbsAdapter的代码例如以下:

/**
* from http://blog.devwiki.net/index.php/2016/07/17/Recycler-View-Adapter-ViewHolder-optimized.html
* RecyclerView.Adapter的扩展,包括headerView/footerView等
* Created by DevWiki on 2016/7/13.
*/ public abstract class AbsAdapter<VH extends BaseHolder> extends RecyclerView.Adapter<BaseHolder> { private static final String TAG = "AbsAdapter"; public static final int VIEW_TYPE_HEADER = 1024;
public static final int VIEW_TYPE_FOOTER = 1025; protected View headerView;
protected View footerView; protected Context context; public AbsAdapter(Context context) {
this.context = context;
} @Override
public final BaseHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_HEADER) {
return new BaseHolder(headerView);
} else if (viewType == VIEW_TYPE_FOOTER) {
return new BaseHolder(footerView);
} else {
return createCustomViewHolder(parent, viewType);
}
} /**
* 创建自己定义的ViewHolder
*
* @param parent 父类容器
* @param viewType view类型{@link #getItemViewType(int)}
* @return ViewHolder
*/
public abstract VH createCustomViewHolder(ViewGroup parent, int viewType); @Override
public final void onBindViewHolder(BaseHolder holder, int position) {
switch (holder.getItemViewType()) {
case VIEW_TYPE_HEADER:
case VIEW_TYPE_FOOTER:
break;
default:
bindCustomViewHolder((VH) holder, position);
break;
}
} @Override
public void onBindViewHolder(BaseHolder holder, int position, List<Object> payloads) {
super.onBindViewHolder(holder, position, payloads);
} /**
* 绑定自己定义的ViewHolder
*
* @param holder ViewHolder
* @param position 位置
*/
public abstract void bindCustomViewHolder(VH holder, int position); /**
* 加入HeaderView
*
* @param headerView 顶部View对象
*/
public void addHeaderView(View headerView) {
if (headerView == null) {
Log.w(TAG, "add the header view is null");
return ;
}
this.headerView = headerView;
notifyDataSetChanged();
} /**
* 移除HeaderView
*/
public void removeHeaderView() {
if (headerView != null) {
headerView = null;
notifyDataSetChanged();
}
} /**
* 加入FooterView
*
* @param footerView View对象
*/
public void addFooterView(View footerView) {
if (footerView == null) {
Log.w(TAG, "add the footer view is null");
return;
}
this.footerView = footerView;
notifyDataSetChanged();
} /**
* 移除FooterView
*/
public void removeFooterView() {
if (footerView != null) {
footerView = null;
notifyDataSetChanged();
}
} /**
* 获取附加View的数量,包括HeaderView和FooterView
*
* @return 数量
*/
public int getExtraViewCount() {
int extraViewCount = 0;
if (headerView != null) {
extraViewCount++;
}
if (footerView != null) {
extraViewCount++;
}
return extraViewCount;
} /**
* 获取顶部附加View数量,即HeaderView数量
* @return 数量
*/
public int getHeaderExtraViewCount() {
return headerView == null ? 0 : 1;
} /**
* 获取底部附加View数量,即FooterView数量
* @return 数量,0或1
*/
public int getFooterExtraViewCount() {
return footerView == null ? 0 : 1;
} @Override
public abstract long getItemId(int position); }

BaseAdapter的代码例如以下:

/**
* from http://blog.devwiki.net/index.php/2016/07/17/Recycler-View-Adapter-ViewHolder-optimized.html
* 基础的Adapter
*
* Created by DevWiki on 2016/7/13.
*/ public abstract class BaseAdapter<M, VH extends BaseHolder> extends AbsAdapter<VH> { private List<M> dataList; public BaseAdapter(Context context) {
super(context);
this.dataList = new ArrayList<>();
} public BaseAdapter(Context context, List<M> list) {
super(context);
this.dataList = new ArrayList<>();
this.dataList.addAll(list);
} /**
* 填充数据,此操作会清除原来的数据
*
* @param list 要填充的数据
* @return true:填充成功并调用刷新数据
*/
public boolean fillList(List<M> list) {
dataList.clear();
boolean result = dataList.addAll(list);
if (result) {
notifyDataSetChanged();
}
return result;
} /**
* 追加一条数据
*
* @param data 要追加的数据
* @return true:追加成功并刷新界面
*/
public boolean appendItem(M data) {
boolean result = dataList.add(data);
if (result) {
if (getHeaderExtraViewCount() == 0) {
notifyItemInserted(dataList.size() - 1);
} else {
notifyItemInserted(dataList.size());
}
}
return result;
} /**
* 追加集合数据
*
* @param list 要追加的集合数据
* @return 追加成功并刷新
*/
public boolean appendList(List<M> list) {
boolean result = dataList.addAll(list);
if (result) {
notifyDataSetChanged();
}
return result;
} /**
* 在最顶部前置数据
*
* @param data 要前置的数据
*/
public void proposeItem(M data) {
dataList.add(0, data);
if (getHeaderExtraViewCount() == 0) {
notifyItemInserted(0);
} else {
notifyItemInserted(getHeaderExtraViewCount());
}
} /**
* 在顶部前置数据集合
*
* @param list 要前置的数据集合
*/
public void proposeList(List<M> list) {
dataList.addAll(0, list);
notifyDataSetChanged();
} @Override
public long getItemId(int position) {
return position;
} @Override
public final int getItemViewType(int position) {
if (headerView != null && position == 0) {
return VIEW_TYPE_HEADER;
} else if (footerView != null && position == dataList.size() + getHeaderExtraViewCount()) {
return VIEW_TYPE_FOOTER;
} else {
return getCustomViewType(position);
}
} /**
* 获取自己定义View的类型
*
* @param position 位置
* @return View的类型
*/
public abstract int getCustomViewType(int position); @Override
public int getItemCount() {
return dataList.size() + getExtraViewCount();
} /**
* 依据位置获取一条数据
*
* @param position View的位置
* @return 数据
*/
public M getItem(int position) {
if (headerView != null && position == 0
|| position >= dataList.size() + getHeaderExtraViewCount()) {
return null;
}
return headerView == null ? dataList.get(position) : dataList.get(position - 1);
} /**
* 依据ViewHolder获取数据
*
* @param holder ViewHolder
* @return 数据
*/
public M getItem(VH holder) {
return getItem(holder.getAdapterPosition());
} public void updateItem(M data) {
int index = dataList.indexOf(data);
if (index < 0) {
return;
}
dataList.set(index, data);
if (headerView == null) {
notifyItemChanged(index);
} else {
notifyItemChanged(index + 1);
}
} /**
* 移除一条数据
*
* @param position 位置
*/
public void removeItem(int position) {
if (headerView == null) {
dataList.remove(position);
} else {
dataList.remove(position - 1);
}
notifyItemRemoved(position);
} /**
* 移除一条数据
*
* @param data 要移除的数据
*/
public void removeItem(M data) {
int index = dataList.indexOf(data);
if (index < 0) {
return;
}
dataList.remove(index);
if (headerView == null) {
notifyItemRemoved(index);
} else {
notifyItemRemoved(index + 1);
}
}
}

參考


http://blog.devwiki.net/index.php/2016/07/17/Recycler-View-Adapter-ViewHolder-optimized.html 《RecyclerView的ViewHolder和Adapter的封装优化》

从头開始学 RecyclerView(三) 封装简化的更多相关文章

  1. 从头開始学 RecyclerView(六) LayoutManager

    前言 在前面的文章中.每一个演示样例,都使用了LayoutManager,毕竟它是RecyclerView必不可少的一部分. LayoutManager,顾名思义,就是『布局管理器』. 使用例如以下代 ...

  2. [php learn] php 从头開始学习1

    前言:大概在2006年的时候,学习过一段时间的php.而且当时做了一个下载的站点,后来因为读研究生阶段用的是java.j2ee相关,所以php就搁浅掉了,php这些年也发生了非常大的变化,最大一个变化 ...

  3. 送给刚刚開始学cocos2d-x引擎 移植Android的同学

    刚刚開始学cocos2-x,不过依照教程把已经安了一般Android的开发环境的eclipse又一次升级到安装好cdt和ndk就花了我几十小时,差点都要放弃了. 參考博客 http://blog.cs ...

  4. 从零開始学Swift之Hello World进化版

    上节课,也就是昨晚啦,我们学习到从零開始学Swift之Hello World.那一节仅仅有一句代码,大家会认为不够过瘾. 那么这节课,就给大家来多点瘾货吧! 先上图! //var 代表变量的类型, s ...

  5. 关东升的《从零開始学Swift》即将出版

    大家好: 苹果2015WWDC大会公布了Swift2.0,它较之前的版本号Swift1.x有非常大的变化.所以我即将出版<从零開始学Swift><从零開始学Swift>将在&l ...

  6. 《PHP 5.5从零開始学(视频教学版)》内容简单介绍、文件夹

    <PHP 5.5从零開始学(视频教学版)>当当网购买地址: http://product.dangdang.com/23586810.html <PHP 5.5从零開始学(视频教学版 ...

  7. 从零開始学android&lt;数据存储(1)SharedPreferences属性文件.三十五.&gt;

    在android中有五种保存数据的方法.各自是: Shared Preferences Store private primitive data in key-value pairs. 相应属性的键值 ...

  8. 【高德地图API】从零開始学高德JS API(五)路线规划——驾车|公交|步行

    先来看两个问题:路线规划与导航有什么差别?步行导航与驾车导航有什么差别? 回答: 1.路线规划,指的是为用户提供3条路线推荐.[高德]在提供路线规划的时候,会提供用户自己定义路线规划功能,这是别家没有 ...

  9. 第13章、布局Layouts之RelativeLayout相对布局(从零開始学Android)

    RelativeLayout相对布局 RelativeLayout是一种相对布局,控件的位置是依照相对位置来计算的,后一个控件在什么位置依赖于前一个控件的基本位置,是布局最经常使用,也是最灵活的一种布 ...

随机推荐

  1. 一步一步做出属于自己的Eclipse

    本文将教大家一步一步打造属于自己的eclipse,涉及到地方,不完全之处请谅解. 一.下载 进入eclipse网站:http://www.eclipse.org/downloads/ 下载:Eclip ...

  2. SRE学习笔记:分布式共识系统、Paxos协议

    最近阅读了<SRE Google运维解密>的第23章,有一些感触,记录一下. 日常工作中,我们经常需要一些服务分布式的运行.跨区域如跨城.跨洲部署运行分布式系统往往是容易的,但是如何保证各 ...

  3. JAVAWEB开发之HttpServletResponse和HttpServletRequest详解(上)(各种乱码、验证码、重定向和转发)

    HttpServletResponse简介 Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象.和代表响应的response对象 request和re ...

  4. 生成模型(Generative Model)和 判别模型(Discriminative Model)

    引入 监督学习的任务就是学习一个模型(或者得到一个目标函数),应用这一模型,对给定的输入预测相应的输出.这一模型的一般形式为一个决策函数Y=f(X),或者条件概率分布P(Y|X). 监督学习方法又可以 ...

  5. [转]PHP: 深入pack/unpack

    From : http://my.oschina.net/goal/blog/195749 http://www.w3school.com.cn/php/func_misc_pack.asp PHP作 ...

  6. [转]MySql ibdata1文件太大如何缩小

    From : http://blog.chinaunix.net/uid-24373487-id-4223322.html 原文地址:MySql ibdata1文件太大如何缩小 作者:emailwht ...

  7. Java NIO Test Case

    package org.zwl.test.nio; import java.io.IOException; import java.net.InetSocketAddress; import java ...

  8. 混沌分形之逻辑斯蒂(Logistic)映射系统

    前几天,有个同事看到我生成的一幅逻辑斯蒂分岔图像后,问我:“这是咪咪吗?”我回答:“淫者见淫.”好吧,这里将生成几种分岔映射图形,包括逻辑斯蒂映射系统,正弦映射系统和曼德勃罗映射系统.实际上这几种图形 ...

  9. @Autowired用法详解

    @Autowired 注释,它可以对类成员变量.方法及构造函数进行标注,完成自动装配的工作. 通过 @Autowired的使用来消除 set ,get方法.在使用@Autowired之前,我们对一个b ...

  10. 【转】 Qt如何设置自动补全快捷键

    原文:https://blog.csdn.net/u014597198/article/details/52797435 在用Qt编程的时,它默认是以“CTRL+空格”来作为自动补全的快捷键的,但是这 ...