1. 程式人生 > >繼承RecyclerView.Adapter使用泛型遇到的問題

繼承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沒有沒提示該錯誤!