0

I am trying to understand what the design is for RecylerView.adapter. The onCreateViewHoldermethod accepts a view type as an argument.

onCreateViewHolder(ViewGroup parent, int viewType)

Called when RecyclerView needs a new RecyclerView.ViewHolder of the given type to represent an item.

This view type is mapped in getItemViewType

getItemViewType(int position)

Return the view type of the item at position for the purposes of view recycling.

And finally when binding the ViewHolder bindViewHolder is called

onBindViewHolder(VH holder, int position)

Called by RecyclerView to display the data at the specified position.

Why is position a parameter in onBindViewHolder? My understanding is that the viewType sent in to onCreateViewHolder allows developers to create an appropriate ViewHolder based on the view type. If this is the case, the position in onBindViewHolder is redundant and unnecessary.

Am I thinking about use of the RecyclerView.adapter class correctly? It makes me question my understanding having the position parameter passed to onBindViewHolder, which seems to scream to be used, but which in my current implementations really doesn't have a need since my ViewHolders are already created using a view type which was mapped from position.

stevebot
  • 23,275
  • 29
  • 119
  • 181

1 Answers1

4

Why is position a parameter in onBindViewHolder?

So you know what data to bind to the ViewHolder. RecyclerView is designed to show a collection of data; a ViewHolder binds one item from that collection to its views.

If this is the case, the position in onBindViewHolder is redundant and unnecessary.

Only if you will always use RecyclerView with a zero- or one-item collection of model data, in which case you should not be using RecyclerView.

my ViewHolders are already created using a view type which was mapped from position

The view type is for views of distinctly different structure, such as headers and details. The view type is independent of position, which is why the position is not passed into onCreateViewHolder().

So, for example, suppose you want to show a vertical-scrolling list of 25 Latin words from a lorem ipsum list. The default is that there is one view type (i.e., you do not override getItemViewType()), and you bind the word to the TextView (or whatever) for the list row in onBindViewHolder().

If, in your implementation of a 25-word-list RecyclerView, you are using 25 view types, most likely you are doing it wrong. The only case where that might vaguely be appropriate is if each row will be very different in structure (first row is a TextView, second row is an ImageButton, third row is an ImageView plus a Switch, etc.).

As an example, here is an activity that hosts a RecyclerView to show a 25-word list:

/***
  Copyright (c) 2008-2015 CommonsWare, LLC
  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  use this file except in compliance with the License. You may obtain   a copy
  of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
  by applicable law or agreed to in writing, software distributed under the
  License is distributed on an "AS IS" BASIS,   WITHOUT WARRANTIES OR CONDITIONS
  OF ANY KIND, either express or implied. See the License for the specific
  language governing permissions and limitations under the License.

  From _The Busy Coder's Guide to Android Development_
    https://commonsware.com/Android
*/

package com.commonsware.android.recyclerview.simplelist;

import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends RecyclerViewActivity {
  private static final String[] items={"lorem", "ipsum", "dolor",
          "sit", "amet",
          "consectetuer", "adipiscing", "elit", "morbi", "vel",
          "ligula", "vitae", "arcu", "aliquet", "mollis",
          "etiam", "vel", "erat", "placerat", "ante",
          "porttitor", "sodales", "pellentesque", "augue", "purus"};

  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);

    setLayoutManager(new LinearLayoutManager(this));
    setAdapter(new IconicAdapter());
  }

  class IconicAdapter extends RecyclerView.Adapter<RowHolder> {
    @Override
    public RowHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      return(new RowHolder(getLayoutInflater()
                            .inflate(R.layout.row, parent, false)));
    }

    @Override
    public void onBindViewHolder(RowHolder holder, int position) {
      holder.bindModel(items[position]);
    }

    @Override
    public int getItemCount() {
      return(items.length);
    }
  }

  static class RowHolder extends RecyclerView.ViewHolder {
    TextView label=null;
    TextView size=null;
    ImageView icon=null;
    String template=null;

    RowHolder(View row) {
      super(row);

      label=(TextView)row.findViewById(R.id.label);
      size=(TextView)row.findViewById(R.id.size);
      icon=(ImageView)row.findViewById(R.id.icon);

      template=size.getContext().getString(R.string.size_template);
    }

    void bindModel(String item) {
      label.setText(item);
      size.setText(String.format(template, item.length()));

      if (item.length()>4) {
        icon.setImageResource(R.drawable.delete);
      }
      else {
        icon.setImageResource(R.drawable.ok);
      }
    }
  }
}

This extends a simple RecyclerViewActivity I cobbled together as a counterpart to ListActivity, but most of the logic is here, in the Adapter and ViewHolder. You can also view the full project, and ~20 RecyclerView sample projects overall, if desired.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491