首先讲一下三者的关系,ViewGroup是一个可以包含很多个子View的类,每一个列表项都是作为一个View子对象显示的,每个View可以是简单的也可以是复杂的。
这里假设每个View都是一个TextView,而且一个屏幕可以显示10个TextView
,现在有上百个TextView要显示,那是不是意味着要准备上百个TextView呢?不是,这里涉及到回收利用的思想,并且已经封装成了RecylerView类。RecyclerView可以创建刚刚好充满屏幕的10个视图,用户滑动屏幕切换视图时,上一个视图就被回收利用并且加载下一个将要显示的视图。
RecyclerView的任务就是
回收和定位屏幕上的View
。
列表项View显示数据涉及
Adapter和ViewHolder。
ViewHolder只做一件事,就是
容纳View视图。
RecyclerView并不会创建视图,它创建的是ViewHolder,而ViewHolder分别引用着一个个itemView。不过
RecyclerView自己也是不直接创建ViewHolder
的,这个任务是adapter完成的。Adapter是一个控制器(适配器)对象,从模型层获取数据,然后提供给RecyclerView显示,起到桥梁的作用。
Adapter负责任务有2个:
1.创建必要的ViewHolder;
2.绑定ViewHolder到模型层数据。
.
创建Adapter,首先要定义RecyclerView.Adapter,然后由他封装获取的数据。
RecyclerView要视图时,就会去找它的Adapter:
1)先调用Adapter的getItemCount()方法,询问数组列表中的对象数量。
2)RecyclerView调用adapter的createViewHolder(ViewGroup,int)方法创建ViewHolder以及ViewHolder要显示的视图。
3)RecyclerView会传入ViewHolder及其位置,调用onBindViewHolder(ViewGroup,int)方法。adapter会找到目标位置的数据并且绑定到ViewHolder视图上。绑定就是使用模型数据填充视图。
三个过程完成后,RecyclerView就能在屏幕上显示View了,另外createViewHolder以及onBindViewHolder使用并不频繁。创建了够用的ViewHolder就停止调用了。然后会自动回收旧的ViewHolder来节约时间和节省内存。
1.RecyclerView的使用:
在project的build.gradle添加:
allprojects {
repositories {
jcenter()
maven{
url "https://maven.google.com"
}
}
}
在app的
build.gradle添加:
compile 'com.android.support:cardview-v7:26.+'
compile 'com.android.support:recyclerview-v7:26.+'
布局文件中这样引用:
<android.support.v7.widget.RecyclerView
android:id="@+id/shoppinglist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible"
/>
这样就创建了一个空的
RecyclerView,在代码中获取
RecyclerView后,设置其显示方式:
然后使用Adapter为它填充数据:
mRecyclerView.setAdapter(mAdapter);
在
RecyclerView中必须自定义实现
RecyclerView.Adapter提供数据集合,实现时要遵循ViewHolder设计模式。
2.自定义RecyclerView.ViewHolder,代码中就是以上思想的实现
public class ViewHolder extends RecyclerView.ViewHolder {
private SparseArray<View> mViews;//存储list_Item的View
private View mConvertView;//list_Item
public ViewHolder(Context context, View itemView, ViewGroup parent) {
super(itemView);
mConvertView=itemView;
mViews=new SparseArray<View>();
}
//获取实例
public static ViewHolder get(Context context,ViewGroup parent,int layoutId) {
View itemView= LayoutInflater.from(context).inflate(layoutId,parent,false);
ViewHolder holder=new ViewHolder(context,itemView,parent);
return holder;
}
public <T extends View> T getView(int viewId) {
View view=mViews.get(viewId);
if(view==null) {
view=mConvertView.findViewById(viewId);
mViews.put(viewId,view);
}
return (T)view;
}
}
3.自定义
RecyclerView.Adapter:
public abstract class CommonAdapter extends RecyclerView.Adapter<ViewHolder> {
private List<Map<String,Object>> mdatas;//要显示的数据
private OnItemClickListener mOnItemClickListener;//列表点击监听器
private Context mContext;
private int mLayoutId;
public CommonAdapter(Context context,int layoutId,List datas) {
mContext=context;
mLayoutId=layoutId;
mdatas=datas;
}
public void removeItem(int i) {//非必要,只是为了调用删除函数方便
if(i>0) {
mdatas.remove(i);
notifyItemRemoved(i);
}
}
//开始三个过程的实现
@Override
public int getItemCount() {
return mdatas.size();
}
@Override
public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
ViewHolder viewHolder=ViewHolder.get(mContext,parent,mLayoutId);
return viewHolder;
}
@Override
public void onBindViewHolder(final ViewHolder holder,int position) {
if(mOnItemClickListener!=null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onClick(holder.getAdapterPosition());
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mOnItemClickListener.onLongClick(holder.getAdapterPosition());
return true;
}
});
}
convert(holder,mdatas.get(position));
}
public void convert(ViewHolder holder,Map<String,Object> s) {}//根据自己意愿绑定数据
public interface OnItemClickListener{
void onClick(int position);
void onLongClick(int position);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.mOnItemClickListener=onItemClickListener;
}
}
在创建的时候重载convert函数(绑定数据到itemview上的哪里):
CommonAdapter commonAdapter=new CommonAdapter(this,R.layout.shoppinglist,listItems) {
@Override
public void convert(ViewHolder holder,Map<String,Object> s) {
TextView name=holder.getView(R.id.goodsName);
name.setText(s.get("name").toString());
TextView first=holder.getView(R.id.goodsFirst);
first.setText(s.get("firstLetter").toString());
}
};
利用所学可以实现一个小项目:
https://github.com/KingsonKai/AndroidProject/tree/master/Lab3