Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

android - ListView to RecyclerView Migration for CustomView

I see a need in my project to move from ListView to RecyclerView. I am facing some design issue.

In my current ListView implementation I am using CustomView instead of inflating there. Here is my current 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;

}

here showView manages populates textViews, Images custom LayoutParams and while lot of other stuff (2000 lines).

Now as I am planning to move to RecylerView I am little confuse about my design. - Do I need to rewrite whole thing in RecyclerView.ViewHolder class and then bind those in onBindViewHolder?

As I already wrote good chunk of code for Listview and I don't want to rewrite/move whole stuff back from CustomView to ViewHolder.

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

It's pretty straight-forward to translate your ListView adapter to a RecyclerView.Adapter - I've written skeletons for both implementations below:

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.

The philosophy behind RecyclerView is separation of concerns; the RecyclerView is responsible only for managing view recycling, the LayoutManager will decide how views are measured and positioned, the ViewHolder is an attempt to force the ViewHolder pattern (an approach to avoid multiple unnecessary calls to findViewById()), and the RecyclerView.Adapter is the glue that hooks your data up.

You're now forced to use the ViewHolder class. The idea is do all your findViewById() calls only once per inflated layout (whether or not this call is slow enough to bother doing is debated), e.g.:

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);
    }

}

Actually, since you're using a custom View, it's very likely (I hope), that you're already avoiding multiple calls to findViewById(int) by using the HolderView pattern. In which case you can rebel against the tyranny of mandated ViewHolder usage by treating it as necessary evil:

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);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...