从头开始学 RecyclerView(三) 封装简化

前言



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

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
     * @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 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的封装优化》

时间: 2025-01-13 22:01:26

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

从头开始学 RecyclerView(二) 添加item点击事件

不管了,先来张图 偶吐了个槽 item点击事件必须手动添加,默认并没有一个显式的API接口可供调用. 为了节约学习时间,网上找了篇很不错的文章.这里基本就复制了. 添加点击事件 RecyclerView#addOnItemTouchListener 分析 查看RecyclerView源码可以看到,RecyclerView预留了一个Item的触摸事件方法: public void addOnItemTouchListener(OnItemTouchListener listener) { mOnI

从头开始学 RecyclerView(五) ItemDecoration 详解

前言 RecyclerView.ItemDecoration,通过名字来看,它就是用来装饰Item的. 在类ListView的视图中,可能需要绘制分隔线:在类GridView的网格视图中,可能需要绘制单元格样式- 这些都可以由重写RecyclerView.ItemDecoration来进行定制. 然后调用mRecyclerView.addItemDecoration(itemDecoration); 即可 分析 看下RecyclerView.ItemDecoration的源码: public s

从头开始学 RecyclerView(六) LayoutManager

前言 在前面的文章中,每个示例,都使用了LayoutManager,毕竟它是RecyclerView不可缺少的一部分. LayoutManager,顾名思义,就是『布局管理器』. 使用如下代码,设置RecyclerView的LayoutManager: mRecyclerView.setLayoutManager(layoutManager); 已提供的LayoutManager android.support.v7.widget.LinearLayoutManager android.supp

从头开始学JavaScript (三)——数据类型

一.分类 基本数据类型:undefined.null.string.Boolean.number 复杂数据类型:object object的属性以无序的名称和值对的形式 (name : value) 来定义 二.详解 1.undefined:undefined类型只有一个值:undefined,在使用var对变量进行声明但未初始化时,这个变量的值就是undefined. 包含undefined值的变量与尚未定义的变量是不一样的,以下这个例子可以说明: var demo1;//声明但未初始化 al

从头开始学JavaScript (十一)——Object类型

原文:从头开始学JavaScript (十一)--Object类型 一.object类型 一个object就是一系列属性的集合,一个属性包含一个名字(属性名)和一个值(属性值). object对于在应用程序中存储和传输数据而言,是非常理想的选择 二.创建object 创建object实例有两种方法: 使用new 操作符后跟object构造函数 使用对象初始化器,也就是对象字面量表示法 2.1使用new 操作符后跟object构造函数创建object实例: 1 var person = new O

从头开始学JavaScript (十)——垃圾收集

原文:从头开始学JavaScript (十)--垃圾收集 一.垃圾收集 1.1javascript垃圾收集机制: 自动垃圾收集,执行环境会负责管理代码执行过程中的使用的内存.而在C和C++之类的语言中,开发人员的一项基本任务就是手动跟踪内存的使用情况,这是造成许多问题的一个根源.在编写javascript程序时候,开发人员不用再关心内存使用的问题,所需内存的分配 以及无用的回收完全实现了自动管理. 1.2垃圾收集原理: 找出那些不再继续使用的变量,然后释放其中占用的内存. 垃圾收集器会按照固定的

从头开始学JavaScript (七)——函数

原文:从头开始学JavaScript (七)--函数 一.return 函数在执行完return之后停止并立即退出. return返回值:与return: 如下两个例子: 1 function sum(num1, num2) { 2 num1= num1 + num2; 3 return num1; 4 } 5 6 var result = sum(5, 10); 7 alert(result);//15 function sum(num1, num2) { num1= num1 + num2;

从头开始学JavaScript (六)——语句

原文:从头开始学JavaScript (六)--语句 一.条件分支语句:if 基本格式: if (<表达式1>){    <语句组1>}else if (<表达式2>){    <语句组2>}else{    <语句组3>} 执行流程: 二.循环语句 2.1前测试循环语句:在循环体内的代码被执行之前就对出口条件求值. 2.1.1while语句 基本格式: do {    <语句组>} while (<表达式>)  执行流程

从头开始学JavaScript (四)——操作符

原文:从头开始学JavaScript (四)--操作符 一.一元操作符 1.自增自减操作符:分为前置型和后置型: 前置型:++a;--a; 后置型:a++;a--; 例: 1 <script type="text/javascript"> 2 var a, b,i= 1,j=1; 3 a=i++; 4 b=++j; 5 alert("a="+a+",i="+i+",b="+b+",j="+j);