CustomView 的 ListView 到 RecyclerView 迁移

ListView to RecyclerView Migration for CustomView

我发现我的项目需要从 ListView 转移到 RecyclerView。我遇到了一些设计问题。

在我当前的 ListView 实现中,我使用 CustomView 而不是在那里膨胀。这是我当前的 getView()

public View getView(int position, View containerRow, ViewGroup parent) {
        CustomView customView;
        if (containerRow == null) customView = new CustomView(mContext);
        else customView = (CustomView) containerRow;

        DataModel dataModel = getModelForPosition(position);
        if (dataModel != null) {
            customView.showView(singleDcyde,position);
        }
        return customView;

}

此处 showView 管理填充文本视图、图像自定义 LayoutParams 以及许多其他内容(2000 行)。

现在我正计划转移到 RecylerView,我对我的设计有点困惑。 - 我是否需要在 RecyclerView.ViewHolder class 中重写整个内容,然后在 onBindViewHolder 中绑定它们?

因为我已经为 Listview 编写了大量代码,所以我不想 rewrite/move 将所有内容从 CustomView 返回到 ViewHolder。

保持设计与 RecyclerView 理念同步的最佳方法是什么。

将 ListView 适配器转换为 RecyclerView.Adapter 非常简单 - 我已经为以下两种实现编写了框架:

private static class MyRecyclerViewAdapter extends RecyclerView.Adapter<CustomViewHolder> {

    @Override
    public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        CustomView view = createNewCustomView();
        return new CustomViewHolder(view);
    }

    private CustomView createNewCustomView() {
        // whatever you need to do to create - I would suggest create from XML rather new'ing up directly
        return null;
    }

    @Override
    public void onBindViewHolder(CustomViewHolder holder, int position) {
        // bind the data
        DataModel dataModel = getModelForPosition(position);
        holder.getCustomView().showView(dataModel, position);
    }

    private DataModel getModelForPosition(int position) {
        // TODO: however you did getModelForPosition(int)
        return null;
    }

    @Override
    public int getItemCount() {
        // TODO: same as getCount()
        return 0;
    }

}

private static class CustomViewHolder extends RecyclerView.ViewHolder {

    public CustomViewHolder(CustomView itemView) {
        super(itemView);
    }

    CustomView getCustomView() {
        return ((CustomView) itemView);
    }

}

private static class MyListViewAdapter extends BaseAdapter {

    @Override
    public int getCount() {
        // TODO: return correct list size
        return 0;
    }

    @Override
    public DataModel getItem(int position) {
        // TODO: however you did getModelForPosition(int)
        return null;
    }

    @Override
    public long getItemId(int position) {
        // however you do
        return 0;
    }

    @Override
    public View getView(int position, View containerRow, ViewGroup parent) {
        CustomView customView = ((CustomView) containerRow);
        if (customView == null) {
            customView = createNewCustomView();
        }

        // could just use getItem(int) here
        DataModel dataModel = getModelForPosition(position);

        // would it ever be null? if so, you'll have a blank list item
        if (dataModel != null) {
            customView.showView(dataModel.getSingleDcyde(), position);
        }
        return customView;
    }

    private CustomView createNewCustomView() {
        // whatever you need to do to create - I would suggest create from XML rather new'ing up directly
        return null;
    }

    private DataModel getModelForPosition(int position) {
        return getItem(position);
    }

}

private static class DataModel {

    Object getSingleDcyde() {
        // whatever this is
        return null;
    }

}

private static class CustomView extends View {

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void showView(Object singleDcyde, int position) {
        // bind
    }

}

What is the best way to keep design in sync with RecyclerView philosophy.

RecyclerView 背后的理念是关注点分离; RecyclerView 仅负责管理视图回收,LayoutManager 将决定如何测量和定位视图,ViewHolder 试图强制使用 ViewHolder 模式(一种避免多次不必要地调用 findViewById() 的方法),以及 RecyclerView.Adapter 是连接数据的粘合剂。

您现在被迫使用 ViewHolder class。这个想法是每个膨胀布局 (whether or not this call is slow enough to bother doing is debated) 只执行一次所有 findViewById() 调用,例如:

private static final class CustomViewHolder extends RecyclerView.ViewHolder {

    private final TextView titleTextView;
    private final ImageView avatarImageView;

    public CustomViewHolder newInstance(CustomView itemView) {
        return new CustomViewHolder(
                itemView,
                ((TextView) itemView.findViewById(R.id.title_text_view)),
                ((ImageView) itemView.findViewById(R.id.avatar_image_view))
        );
    }

    private CustomViewHolder(CustomView itemView, TextView titleTextView, ImageView avatarImageView) {
        super(itemView);
        this.titleTextView = titleTextView;
        this.avatarImageView = avatarImageView;
    }

    public void setTitle(String title) {
        titleTextView.setText(title);
    }

    public void setAvatar(Drawable avatar) {
        avatarImageView.setImageDrawable(avatar);
    }

}

实际上,由于您使用的是自定义视图,很可能(我希望)您已经通过使用 HolderView pattern 避免了对 findViewById(int) 的多次调用。在这种情况下,您可以通过将其视为必要的邪恶来反抗强制使用 ViewHolder 的暴政:

private static final class CustomViewHolder extends RecyclerView.ViewHolder {

    public CustomViewHolder(CustomView itemView) {
        super(itemView);
    }

}

...
...

@Override
public void onBindViewHolder(CustomViewHolder holder, int position) {
    Foo foo = getFoo(position);
    ((CustomView) holder.itemView).myCustomBindMethod(foo);
}