繼承RecyclerView.Adapter使用泛型遇到的問題
轉自:http://my.oschina.net/buobao/blog/651007
在使用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沒有沒提示該錯誤!