7

What if I have 50 types of views? Should I have 50 static inner classes in my adapter? According to this answer, yes.

My first thought was to move each viewholder inner class into a seperate public class, but they have to be static. So encapsulate each one into a public class, to make the inner class static? Are there any nicer alternatives?

edit: code sample: So this would be a good solution? Doesn't this also kill performance?

public class MainViewHolder extends DragSortAdapter.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
View container;
TextView title;

//called in onCreateViewHolder in adapter
public MainViewHolder(DragSortAdapter adapter, View itemView) {
    super(adapter, itemView);

    container = itemView.findViewById(R.id.card_root);

    title = container.findViewById(R.id.text);
}
//called by onBindViewHolder in adapter
public void setData(Data data) {
    title.setText(data.title);
}
}

edit2: sample, for when a new instance is returned of the viewholder

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
     switch (viewType) {
         case 0: return new MainViewHolder(...);
         case 2: return new MainViewHolderOther(...);
         ...
     }
}
Community
  • 1
  • 1
Tamas
  • 360
  • 1
  • 4
  • 13
  • Why do you think a top-level class isn't static? Can you add some code examples to clarify what you mean? – nhaarman Mar 12 '15 at 09:39
  • why do they have to be static ? – Blackbelt Mar 12 '15 at 09:39
  • @NiekHaarman top level public class cannot be static in java. – Tamas Mar 12 '15 at 09:44
  • @Blackbelt viewholder pattern demands it :) – Tamas Mar 12 '15 at 09:44
  • 2
    @Tamas A top-level class is static by definition. And the ViewHolder pattern 'demands' it so the ViewHolder instance does not have an reference to its outer class. Making the static inner ViewHolder class a top-level class has exactly the same result. – nhaarman Mar 12 '15 at 09:44
  • @NiekHaarman if my viewholders are just public classes, and I'm just returning a new instance every time, then the findviewbyids are killing my ui. – Tamas Mar 12 '15 at 09:53
  • @Tamas This really needs some example code to see exactly where the problem lies for you. – nhaarman Mar 12 '15 at 09:54
  • @NiekHaarman added code sample. So what I mean is, if my viewholder is just in some public class, and I'm getting a new instance every time, does it not kill performance? – Tamas Mar 12 '15 at 10:01
  • You won't necessarily be creating a new instance everytime. Why do you think that? Could you add that part as well? – nhaarman Mar 12 '15 at 10:11
  • @NiekHaarman added sample. I'm using it the same way as the docs tell me. – Tamas Mar 12 '15 at 10:15
  • I am still not sure why you think there's a difference between a static inner class or a top-level class. This `onCreateViewHolder` method will only get called if absolutely necessary, say max `10*typeCount` depending on the size of the Views and their ordering. – nhaarman Mar 12 '15 at 10:18
  • @NiekHaarman shouldn't it be only called once per viewtype? I have a bunch of views, and they're really killing performance. – Tamas Mar 12 '15 at 10:53
  • It is called whenever Android needs to show a `View` for given type, but there is no recycled `View` available. For example, if you have only 1 type, 20 items, and 7 of them fit on the screen, `onCreateViewHolder` will be called roughly 7-8 times for all 20 items. – nhaarman Mar 12 '15 at 10:55
  • @NiekHaarman I see. I have the opposite btw, 20 types, 1 item each. So just to sum up the answer to my original question: I can freely put all my viewholder classes in public classes, it won't make a difference, compared to them beeing static inner classes. – Tamas Mar 12 '15 at 11:09
  • 2
    If you have 20 types, 1 item each, the `ViewHolder` pattern has no effect. The `ViewHolder` pattern is only useful when the same `View` can be reused for several items in the `ListView`. This raises the question whether you really actually need to have the 20 types. For example, a different background color does not need to be a different type. – nhaarman Mar 12 '15 at 11:12
  • I have a dashboard style screen, which at this time has unique cards, that can be reordered, in a staggered view. Later there will be cards, that reuse the same ui, but have minor variations. That's why I went for recyclerview and the viewholder pattern. – Tamas Mar 12 '15 at 11:49

1 Answers1

9

You can use only one viewHolder inner class to handle lots of different viewType. Firstly you have to use getItemViewType(viewType) to get the item position and also have to use viewHolder according to viewType Position.

Make One vieHolder inner class in which you can pass view and viewtype according to position of item and inflate the layout as shown below code. Code sample is given below.

public class Adapter extends
        RecyclerView.Adapter<Adapter.MyViewholder> {

LayoutInflater inflater;
private Context context;
ArrayList<Detail> data = new ArrayList<Detail>();

public Adapter(Context context, ArrayList<Detail> getdata) {
    this.context = context;
    inflater = LayoutInflater.from(context);
    this.data = getdata;
}

class MyViewholder extends RecyclerView.ViewHolder {
    TextView txtRow, txt_rec;

    public MyViewholder(View view, int type) {
        super(view);

        if (type == Constants.NORMAL) {
            txtRow = (TextView) view
                    .findViewById(R.id.txtRow);
        } else if (type == Constants.RECORDING) {
            txt_rec = (TextView) view
                    .findViewById(R.id.txt_rec);
        } 
    }
}

@Override
public int getItemCount() {
    return data.size();
}

@Override
public void onBindViewHolder(MyViewholder viewholder, int position) {
    int listViewItemType = getItemViewType(position);
    Detail detail = data.get(listViewItemType);
    if (detail.getType() == Constants.NORMAL) {
        viewholder.txtRow.setText(detail.getKey());
    } else if (detail.getType() == Constants.RECORDING) {
        viewholder.txt_rec.setText(detail.getRecording());
    } 

}

@Override
public MyViewholder onCreateViewHolder(ViewGroup parent, int viewType) {

    int listViewItemType = getItemViewType(viewType);
  switch (listViewItemType) {
         case 0: 
              view = inflater.inflate(R.layout.detail_item, parent,
                    false);
            myViewholder = new MyViewholder(view, Constants.NORMAL);
         case 2: 
             view = inflater.inflate(R.layout.recording, parent, false);
            myViewholder = new MyViewholder(view, Constants.RECORDING);
    }
    return myViewholder;
}

@Override
public int getItemViewType(int position) {
        return position;
    }
}

Hope this code will help you

Amandeep Rohila
  • 3,558
  • 2
  • 28
  • 34