Search code examples
androidadapterandroid-viewholder

Example of implementing ViewHolder with multiple layouts


I managed to implement ViewHolder in my adapter but since I am rather new to this, I am not sure if the following implementation is correct. I have 10 elements in my array at the moment but I spent around 3-4 minutes debugging and I'm not sure I understand the workflow of the View Holder. I know this is not necessarily a question, but I would like to have this checked in case it's written badly.

@Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        COLOR_GREEN = R.color.ck_in_category_green;
        View rowView = convertView;
        ViewHolder holder;

        int type = getItemViewType(position);
        if (convertView == null) {
            holder = new ViewHolder();
            switch (type) {
                case TYPE_MINE_OR_ACCEPTED:
                    convertView = View.inflate(context, R.layout.item_notif_mine_or_accepted, null);
                    rowView = handleViewForMineOrAccepted(holder, convertView, checkIns.get(position));
                    break;
                case TYPE_TAGGING:
                    convertView = View.inflate(context, R.layout.item_notif_tagged_or_invited, null);
                    rowView = handleViewForTaggingOrInvitation(holder, convertView, checkIns.get(position), true);
                    break;
                case TYPE_INVITATION:
                    convertView = View.inflate(context, R.layout.item_notif_tagged_or_invited, null);
                    rowView = handleViewForTaggingOrInvitation(holder, convertView, checkIns.get(position), false);
                    break;
            }
            rowView.setTag(holder);
        } else {
            holder = (ViewHolder) rowView.getTag();
            switch (type) {
                case TYPE_MINE_OR_ACCEPTED:
                    rowView = handleViewForMineOrAccepted(holder, convertView, checkIns.get(position));
                    break;
                case TYPE_TAGGING:
                    rowView = handleViewForTaggingOrInvitation(holder, convertView, checkIns.get(position), true);
                    break;
                case TYPE_INVITATION:
                    rowView = handleViewForTaggingOrInvitation(holder, convertView, checkIns.get(position), false);
                    break;
            }
        }
        return rowView;
    }

One of the handleView methods :

private View handleViewForMineOrAccepted(final ViewHolder holder, View view, final Checkin checkin) {
        holder.checkInPicture = (ImageView) view.findViewById(R.id.mine_or_accepted_check_in_picture);
        holder.locationSmall = (TextView) view.findViewById(R.id.check_in_location_small);
        holder.locationBig = (TextView) view.findViewById(R.id.check_in_location_big);
        holder.creatorFrame = (RelativeLayout) view.findViewById(R.id.check_in_creator_frame);

        holder.tagged1Layout = (RelativeLayout) view.findViewById(R.id.notif_check_in_tagged_1);
        holder.tagged2Layout = (RelativeLayout) view.findViewById(R.id.notif_check_in_tagged_2);
        holder.tagged3Layout = (RelativeLayout) view.findViewById(R.id.notif_check_in_tagged_3);

        holder.time = (TextView) view.findViewById(R.id.join_request_check_in_time);
        holder.calendar = (ImageView) view.findViewById(R.id.join_request_time_icon);

        holder.creator = (ImageView) view.findViewById(R.id.confirmed_friend_1);
        holder.tagged1 = (ImageView) view.findViewById(R.id.confirmed_friend_2);
        holder.tagged2 = (ImageView) view.findViewById(R.id.confirmed_friend_3);
        holder.tagged3 = (ImageView) view.findViewById(R.id.confirmed_friend_4);
        holder.tagged1Layout.setVisibility(View.GONE);
        holder.tagged2Layout.setVisibility(View.GONE);
        holder.tagged3Layout.setVisibility(View.GONE);

followed by some logic, click events, etc.


Solution

  • From my experience its the best to extend BaseAdapter to generate clean methods for binding Views to ViewHolder - thats a BaseAdapter how i use it everywhere (where i'm still using listview instead of recyclerview)

    public abstract class MyBaseAdapter extends BaseAdapter {
    
    protected LayoutInflater inflater;
    protected Context context;
    
    public TikBaseAdapter(Context context) {
        this.context = context;
        this.inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }
    
    public final View getView(int position, View convertView, ViewGroup parent) {
        int type = getItemViewType(position);
        if (convertView == null) {
            convertView = newView(type, parent);
        }
        bindView(position, type, convertView);
        return convertView;
    }
    
    /** Create a new instance of a view for the specified {@code type}. */
    public abstract View newView(int type, ViewGroup parent);
    
    /** Bind the data for the specified {@code position} to the {@code view}. */
    public abstract void bindView(int position, int type, View view);
    
    
    
    }
    

    your code looks good as far as i can see - but you're calling findView everytime when "binding" the view - that's unneccessary.

    with my BaseAdapter you set the viewHolder to the convertView in newView() and already call findViewById to reference all the views. in bindView() you just get the viewHolder via convertView.getTag() and set things on the views e.g.: holder.title.setText(item.getTitle())