-1

I know it's a bad idea, but I'm using a RecyclerView inside another RecyclerView's item to display a list of items containing a list.

I managed to get it work and tweaked it as far as I could, but I still get those green spikes when lists with a bigger number of items begin to show and are being drawn on the screen.

GPU profiling Samsung Galaxy S6

Those spikes produce a noticeable lag when flinging through items and are even more obvious when using something slower and older than Samsung Galaxy S6.

I did some logging, and it appears that the outer ViewHolders are being recycled and the inner RecyclerView's adapter is created only 5 times so it must be the drawing time that kills the performance.

I've managed to limit the creation of new inner RecyclerView's ViewHolders by setting the maximum number of ViewHolders in the RecycledViewPool but that helped only a little.

I know that the inner RecyclerView doesn't have a "bottom" on which it could rely to calculate when to show new items so it has to draw every item immediately and that is probably the main reason why one shouldn't use this setup. (I come to my senses as I write this question.. thank you rubber ducks of the world).

Is there a way this could be tweaked even further or could you suggest how to make this work using some different setup other than RecyclerView inside another RecyclerView's item?

I will provide more info if needed.

Thank you

rexxar
  • 1,671
  • 1
  • 21
  • 27
  • What are you trying to achieve? – Stefan Mar 10 '17 at 11:21
  • 1
    Please do not down-vote the question here..before giving any suggestion to the questioner.. – Ravindra Kushwaha Mar 10 '17 at 11:21
  • trying to get an idea what to do next in order to make this setup fling smoothly, without lagging or dropping frames when flinging – rexxar Mar 10 '17 at 11:23
  • I mean, why are you trying to nest vertically scrolling lists? – Stefan Mar 10 '17 at 11:24
  • thank you for your reply; because I need to display a list of items of which every item has its own list with different number of items and this is what first came to my mind to do and now I see it's not working properly. I've disabled nested scrolling and am using CoordinatorLayout to manage scrolling... – rexxar Mar 10 '17 at 11:28
  • If the recycler's items don't have to be the same size, you can have just one recyclerview with items that differ in height. – Stefan Mar 10 '17 at 11:30
  • ok, but what should be used to display those inner items? – rexxar Mar 10 '17 at 11:31
  • 1
    nested reyclerview's are also in google io 2016 app https://twitter.com/crafty/status/799344328304783360 – Raghunandan Mar 10 '17 at 12:10

2 Answers2

2

The best solution is to either switch back to a ListView and use the ExpandableListView interface, or to implement it yourself on RecyclerView.

As you mentioned - listing scroll components is never a good solution. Here is an example expandable list view adapter so you have an idea what would be required:

public class MyExpandableListAdapter extends BaseExpandableListAdapter {

    ...

    @Override
    public Object getChild(int listPosition, int childListPosition) { 
        //return an item that would have been in one of the nested recyclers
        //(listPosition = parent, childListPosition = nested item number)
       return getGroup(listPosition).getChildren().get(childListPosition);
    }

    @Override
    public int getChildrenCount(int listPosition) {
        //presuming the parent items contain the children
        return getGroup(listPosition).getChildren().size();
    }

    @Override
    public Object getGroup(int listPosition) {
        //group is the parent items (the tope level recycler view items)
        return mData.get(listPosition);
    }

    @Override
    public int getGroupCount() {
        return mData.size();
    }

    @Override
    public View getGroupView(int listPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.list_item, parent, false);
        }
        MyDataType item = getGroup(listPosition);
        //set the fields (or better yet, use viewholder pattern)
        return convertView;
    }

    @Override
    public View getChildView(int listPosition, final int expandedListPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.list_item, parent, false);
        }
        MyDataType item = getChild(listPosition, expandedListPosition);
        //set the fields (or better yet, use viewholder pattern)
        return convertView;
    }

}
Nick Cardoso
  • 20,807
  • 14
  • 73
  • 124
  • thank you, I will check it out and try to implement it. I believed that the days of ListView are over and that the RecyclerView is a must and an Overlord of list views but now I see that it works best if you don't try to mess with it too much – rexxar Mar 10 '17 at 11:33
  • 1
    RecyclerView fixed some problems with ListView but for a case with child items, ExpandableListView still does a lot of the work that you'd have to do yourself in RecyclerView. If you make sure to use the ViewHolder pattern and you're only using a vertical list then there's no problem in using the list view – Nick Cardoso Mar 10 '17 at 11:46
-1

I managed to get better performance by creating a shared RecycledViewPool, as it was done in a project @Raghunandan linked in the comments.

Google I/O Android App - Shared RecycledViewsPool

I also set the max number of views to that Pool which really did the trick, now I just have to find a way to reuse my listeners and avoid creating new ones, but that's a different issue.

Thank you all for responding. I will post more if I find anything useful in the future.

rexxar
  • 1,671
  • 1
  • 21
  • 27