在使用RecyclerView的时候遇到了一个很坑的问题,记录这个大坑!
首先,在使用RecyclerView.Adapter的时候定义了一个BaseListAdapter,代码如下:
public abstract class BaseListAdapter<T extends BaseEntity> extends RecyclerView.Adapter<BaseListAdapter.ViewHolder> {
public static final int ITEM_LAYOUT_NORMAL = 0;
public static final int ITEM_LAYOUT_SIMPLE = 1;
protected List<T> mList;
protected Context mContext;
private int mType;
public int getType(){
return ITEM_LAYOUT_NORMAL;
}
public BaseListAdapter(Context context, List<T> list){
super();
mContext = context;
mList = list;
mType = getType();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int layout = -1;
switch (mType){
case ITEM_LAYOUT_NORMAL:
layout = R.layout.item_list_normal;
break;
case ITEM_LAYOUT_SIMPLE:
layout = R.layout.item_list_simple;
break;
}
View v = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
return new ViewHolder(v);
}
@Override
public int getItemCount() {
return mList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
public TextView title;
public TextView vote;
public ImageView photo;
public TextView content;
public ImageView createrIcon;
public TextView creater;
public TextView date;
public ImageView[] image;
public ViewHolder(View itemView) {
super(itemView);
if (mType == ITEM_LAYOUT_NORMAL) {
title = (TextView) itemView.findViewById(R.id.item_title);
vote = (TextView) itemView.findViewById(R.id.item_vote);
photo = (ImageView) itemView.findViewById(R.id.item_photo);
content = (TextView) itemView.findViewById(R.id.item_content);
createrIcon = (ImageView) itemView.findViewById(R.id.item_user_photo);
creater = (TextView) itemView.findViewById(R.id.item_creater);
date = (TextView) itemView.findViewById(R.id.item_date);
}
if (mType == ITEM_LAYOUT_SIMPLE) {
title = (TextView) itemView.findViewById(R.id.item_title);
image[0] = (ImageView) itemView.findViewById(R.id.item_image1);
image[1] = (ImageView) itemView.findViewById(R.id.item_image2);
image[2] = (ImageView) itemView.findViewById(R.id.item_image3);
image[3] = (ImageView) itemView.findViewById(R.id.item_image4);
image[4] = (ImageView) itemView.findViewById(R.id.item_image5);
}
}
}
}
其中定义的ViewHolder是一个内部类,RecyclerView.Adapter在继承时需要指定泛型,这里看下RecyclerView.Adapter的定义:
public static abstract class Adapter<VH extends ViewHolder> {
private final AdapterDataObservable mObservable = new AdapterDataObservable();
private boolean mHasStableIds = false;
public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
public abstract void onBindViewHolder(VH holder, int position);
public void onBindViewHolder(VH holder, int position, List<Object> payloads) {
onBindViewHolder(holder, position);
}
public final VH createViewHolder(ViewGroup parent, int viewType) {
TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG);
final VH holder = onCreateViewHolder(parent, viewType);
holder.mItemViewType = viewType;
TraceCompat.endSection();
return holder;
}
public final void bindViewHolder(VH holder, int position) {
holder.mPosition = position;
if (hasStableIds()) {
holder.mItemId = getItemId(position);
}
holder.setFlags(ViewHolder.FLAG_BOUND,
ViewHolder.FLAG_BOUND | ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID
| ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN);
TraceCompat.beginSection(TRACE_BIND_VIEW_TAG);
onBindViewHolder(holder, position, holder.getUnmodifiedPayloads());
holder.clearPayload();
TraceCompat.endSection();
}
public int getItemViewType(int position) {
return 0;
}
.......
这里抽象方法onBindViewHolder使用该泛型作为第一个参数。
最后,定义了一个具体的实现adapter,如下:
public class TopicListAdapter extends BaseListAdapter<Topic> {
public TopicListAdapter(Context context, List<Topic> list) {
super(context, list);
}
@Override
public int getType() {
return ITEM_LAYOUT_SIMPLE;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Topic entity = mList.get(position);
holder.title.setText(entity.title);
int index = 0;
if (entity.images != null && entity.images.size() > 0) {
for (String url : entity.images) {
if (index == 5) {
break;
}
Glide.with(mContext)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.placeholder(R.drawable.img_circle_placeholder)
.error(R.drawable.default_photo)
.centerCrop()
.transform(new CropCircleTransformation(mContext))
.into(holder.image[index]);
index++;
}
} else {
for (int i=0;i<5;i++){
holder.image[i].setVisibility(View.GONE);
}
}
}
}
都没有问题,实现类继承抽象类并实现了所有抽象方法。
但是,编译报错!!
居然报的是TopicListAdapter 类中没有实现onBindViewHolder方法,XXX啊!明明实现了,是不是javac有问题啊!
这问题搞的我都怀疑编译器是不是有问题了!!
这里的问题实在是太隐蔽了!上面在抽象类中有一个泛型,这个泛型正好是抽象方法onBindViewHolder的第一个参数类型-》BaseListAdapter.ViewHolder,所以抽象方法的定义是
public abstract void onBindViewHolder(BaseListAdapter.ViewHolder holder, int position);
,而TopicListAdapter中实现的方法是这样的:
public void onBindViewHolder(ViewHolder holder, int position) {
。。。。。
}
有什么不一样?
ViewHolder没有指定是谁的内部类啊!!
改成:
public void onBindViewHolder(BaseListAdapter.ViewHolder holder, int position) {
。。。。。
}
KO!
这里TopicListAdapter 在继承时会继承BaseListAdapter中的内部类ViewHolder,也就是在TopicListAdapter 中也会有ViewHolder这个内部类,所以如果不指定是BaseListAdapter类中的ViewHolder则方法其实是这样定义的:
public void onBindViewHolder(TopicListAdapter.ViewHolder holder, int position) {}
很显然这不是抽象类中定义的方法(参数不一致),所以就造成无法覆盖!
ide没有没提示该错误!