《Android编程权威指南》之使用RecyclerView显示列表

2018-03-01 11:10:37来源:https://www.jianshu.com/p/30d41032e992作者:夜远曦白人点击

分享


第八章了!要坚持走完这本书的坑,真的超级赞的一本技术书喔!


本章的整体规划图:




截取自此书
升级 CriminalIntent 应用的模型层

这里在将crime数组对象将存储在一个单例里,这样就能不管activity和fragment的生命周期怎么变化,随时能获取crime数据。


List<E>是一个泛型类,支持存放特定数据类型的有序列表对象,拥有获取、新增和删除列表元素的方法。


这里的代码还初始化了虚拟数据,100个crime,代码不贴了,照着书老老实实敲吧。


使用抽象 activity 托管 fragment

程序员都是很懒的,最不喜欢重复代码了,这里就是弄了个通用的fragment,并创建了为SingleFragmentActivity的抽象类,把重复代码抽出来了,让其他只有一个fragment的acitivity都继承它。把CrimeListActivity以及它的Fragment代码都写好。


RecyclerView、ViewHolder 和 Adapter

RecyclerView是向用户展示crime列表的控件,它的任务仅限于回收和定位屏幕上的View。


ViewHolder子类做的事是容纳View视图。(ViewHolder 为 itemView 而生:它引用着传给super(view)的整个View视图)




截取自此书
RecyclerView自身不会创建视图,它创建的是ViewHolder , 而 ViewHolder 引用着itemView。



截取自此书

Adapter是一个控制器对象,从模型层获取数据,然后提供给RecyclerView显示,相当于一个桥梁。创建ViewHolder的工作实际上是它做的。

它的工作:


创建必要的ViewHolder
绑定ViewHolder至模型层数据



截取自此书

首先,调用Adapter的getItemCount()方法;接着,RecyclerView调用AdapteronCreateViewHolder(ViewGroup, int)方法创建ViewHolder及其要显示的视图;最后,RecyclerView会传入ViewHolder及其位置,调用onBindViewHolder(ViewHolder, int)方法,找到目标位置的数据并将其绑定到ViewHolder的视图上。

然后就是使用 RecyclerView ,敲代码阶段,记得要添加RecyclerView依赖库,而且依赖库的版本跟引入的appcompat版本保持一致,不然会报错。




image.png

注意,要给RecyclerView去设置LayoutManager,也就是调用setLayoutManager()方法,不然应用会奔溃。实际上,LayoutManager负责了在屏幕上摆放列表项任务,还负责定义屏幕滚动行为。


响应点击

可以让ViewHolder为itemview监听用户触摸事件,即让 CrimeHolder 去 implements View.OnClickListener ,然后用 itemView.setOnClickListener(this); 最后就是在回调用处理点击事件了。


深入学习:ListView 和 GridView

ListView和GridView 也是不关心具体的展示项,只负责展示项的滚动。Adapter负责创建列表项的所有视图。(因为有了RecyclerView,扩展性以及性能都更为优秀,所以已经不再推荐使用ListView以及GridView)


如果crime列表项要从位置0移动到位置5,下面这段代
码就可以做到。


mRecyclerView.getAdapter().notifyItemMoved(0, 5); 

深入学习:单例

单例能方便地存储和控制模型对象,存活时间比fragment或activity久。


缺点:


当切换应用,或逢Android回收内存时,单例也无法做到持久存储。(将文件写入磁盘或是发送到Web服务器是不错的数据持久化存储方案。)
不利于单元测试。(如果应用代码直接调用CrimeLab对象的静态方法,测试时以模拟版本的CrimeLab代替实际CrimeLab实例就不太现实。实践中,Android开发人员会使用依赖注入工具解决这个问题。这个工具允许以单例模式使用对象,对象也可以按需替换。)
挑战练习:RecyclerView ViewType
先在Crime里面增加属性,并创建set、get方法
/* 是否需警方介入 */
private boolean mRequiresPolice;

因为两个item界面就相差一个按钮,所以在list_item_crime.xml中添加一个Button按钮,并设置visibility属性为gone。
同CrimeHolder一样写个CrimePoliceHolder,代码手动把button设置为可见。
定义个枚举类型两个不同类型的item
public enum ITEM_TYPE {
ITEM_TYPE_STANDARD,
ITEM_TYPE_POLICE
}

修改CrimeAdapter
private class CrimeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Crime> mCrimes;
public CrimeAdapter(List<Crime> crimes) {
mCrimes = crimes;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == ITEM_TYPE.ITEM_TYPE_STANDARD.ordinal()) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
return new CrimeHolder(layoutInflater, parent);
} else if (viewType == ITEM_TYPE.ITEM_TYPE_POLICE.ordinal()) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
return new CrimePoliceHolder(layoutInflater, parent);
}
return null;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Crime crime = mCrimes.get(position);
if (holder instanceof CrimeHolder) {
((CrimeHolder) holder).bind(crime);
} else if (holder instanceof CrimePoliceHolder) {
((CrimePoliceHolder) holder).bind(crime);
}
}
@Override
public int getItemViewType(int position) {
if (mCrimes.get(position).isRequiresPolice()) {
return ITEM_TYPE.ITEM_TYPE_POLICE.ordinal();
} else {
return ITEM_TYPE.ITEM_TYPE_STANDARD.ordinal();
}
}
@Override
public int getItemCount() {
return mCrimes.size();
}
}

要过年了,明天回家喽~








最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台