Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

optimizing RecyclerView/ListView

I have a RecyclerView that contains a number of items. Each item is just a TextView, but the padding and font style can change for each item. In terms of the most efficient/smooth scrolling, is it better for me to create a separate layout file for each variable of the item (ie: padding, text style), or can I just set the padding and text style for each item programmatically when the item view is fetched, without having to worry about a performance impact?

Thanks!

like image 820
Wise Shepherd Avatar asked Jan 16 '15 22:01

Wise Shepherd


People also ask

Which is better ListView or RecyclerView?

Simple answer: You should use RecyclerView in a situation where you want to show a lot of items, and the number of them is dynamic. ListView should only be used when the number of items is always the same and is limited to the screen size.

What is nested recycler view?

A nested RecyclerView is an implementation of a RecyclerView within a RecyclerView. An example of such a layout can be seen in a variety of apps such as the Play store where the outer (parent) RecyclerView is of Vertical orientation whereas the inner (child) RecyclerViews are of horizontal orientations.

How many times Oncreateviewholder called?

By default it have 5. you can increase as per your need. Save this answer.


1 Answers

In short, the less work you do in the onBindViewHolder() method, the better the performance of your list view scrolling.

The most efficient implementation would simply take the data from the model that is passed and simply set it to the view holder.

Since all of this work in the onBindViewHolder() method is done on the UI thread, offloading any additional work either prior to the binding or offloaded to anthoer thread is beneficial to list view performance.

For example, lets say that you have a list that contains a bunch of tasks as below:

class Task {
    Date dateDue;
    String title;
    String description;

    // getters and setters here
}

Each task has a title, description and a due date associate with it. As a requirement for your app, if the today's date is before the due date, the row should be green and if passed the due date, it should be red. Also the Task object associated with it requires some special date formatting before setting it to the view.

There are two things that will be done in this onBindViewHolder() as each row is rendered onto the screen:

  • You will need to conditionally check each date and compare it against today's date
  • You will need to apply a date formatter to get the view the date in the required specification:

e.g.

class MyRecyclerView.Adapter extends RecyclerView.Adapter {

    static final TODAYS_DATE = new Date();
    static final DATE_FORMAT = new SimpleDateFormat("MM dd, yyyy");

    public onBindViewHolder(Task.ViewHolder tvh, int position) {
        Task task = getItem(position);

        if (TODAYS_DATE.compareTo(task.dateDue) > 0) {
            tvh.backgroundView.setColor(Color.GREEN);
        } else {
            tvh.backgroundView.setColor(Color.RED);
        }

        String dueDateFormatted = DATE_FORMAT.format(task.getDateDue());
        tvh.dateTextView.setDate(dueDateFormatted);
    }
}

In the above, for every row that is rendered, a date comparison is being made. While we were at it, we even took the liberty to make today's date a constant – object creation is possibly one of the most expensive things you can do in a onBindViewHolder() so any optimization is appreciated. Additionally, the date that is passed in the Task object was not in the proper format so it is formatted that on-the-fly as well.

Although this example is trivial, this can quickly balloon into halting the list view scrolling to a crawl. The better way of doing this is to pass an intermediary object, such as a view model that represents the state of the view instead of the actual business model instead.

Instead of passing your Task as the model to the adapter, we create an intermediatary model called TaskViewModel that is created and set to the adapter. Now before setting any information is sent to the adapter, all of the work is done before any view rendering is applied. This comes at the cost of longer initialization time prior to sending data to your RecyclerView but at the better trade-off of list view performance.

This view model instead could be:

public class TaskViewModel {
    int overdueColor;
    String dateDue;
}

Now when tasked to bind the data to the view, we have the actual view state being represented in the view model and our UI thread can continue to be jank free.

public onBindViewHolder(Task.ViewHolder tvh, int position) {
    TaskViewModel taskViewModel = getItem(position);
    tvh.backgroundView.setColor(taskViewModel.getOverdueColor());
    tvh.dateTextView.setDate(taskViewModel.getDateDue());
}
like image 69
Marvin Bernal Avatar answered Oct 11 '22 07:10

Marvin Bernal