优化RecyclerView/ListView

Wis*_*erd 8 android android-listview android-recyclerview

我有一个包含许多项目的RecyclerView.每个项目只是一个TextView,但填充和字体样式可以为每个项目更改.在最有效/平滑的滚动方面,我是否更好地为项目的每个变量创建一个单独的布局文件(即:填充,文本样式),或者我可以只是以编程方式为每个项目设置填充和文本样式何时获取项目视图,而不必担心性能影响?

谢谢!

Aer*_*lon 6

简而言之,您在onBindViewHolder()方法中所做的工作越少,列表视图滚动的性能就越好。

最有效的实现方式是简单地从传递的模型中获取数据,然后将其设置为视图持有者。

由于该onBindViewHolder()方法中的所有这些工作都是在UI线程上完成的,因此,在绑定之前或将其转移到其他线程之前,将所有其他工作都卸载对列表视图性能很有帮助。

例如,假设您有一个包含一堆任务的列表,如下所示:

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

    // getters and setters here
}
Run Code Online (Sandbox Code Playgroud)

每个任务都有一个标题,描述和到期日期。根据您的应用要求,如果今天的日期早于到期日,则该行应为绿色,如果超过了到期日,则应为红色。此外,Task与之关联的对象在将其设置为视图之前还需要一些特殊的日期格式。

onBindViewHolder()每一行呈现到屏幕上时,将完成两件事:

  • 您将需要有条件地检查每个日期,并将其与今天的日期进行比较
  • 您将需要使用日期格式化程序来获取所需规范中的日期视图:

例如

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面,对于呈现的每一行,都将进行日期比较。在进行此操作时,我们甚至可以自由地使今天的日期保持不变–对象创建可能是您可以在其中进行的最昂贵的操作之一,onBindViewHolder()因此任何优化都值得赞赏。此外,Task对象中传递的日期格式不正确,因此它也可以即时格式化。

尽管这个例子很简单,但是它可以迅速停止列表视图滚动到爬网。更好的方法是传递一个中间对象,例如表示视图状态的视图模型,而不是实际的业务模型。

我们没有将您Task的模型传递给适配器,而是创建了一个称为的中间模型TaskViewModel,该模型被创建并设置为适配器。现在,在将任何信息设置发送到适配器之前,所有工作都在应用任何视图呈现之前完成。这是以在将数据发送到您之前要花费较长的初始化时间为代价的,但代价是要RecyclerView更好地权衡列表视图的性能。

该视图模型可能是:

public class TaskViewModel {
    int overdueColor;
    String dateDue;
}
Run Code Online (Sandbox Code Playgroud)

现在,当任务是将数据绑定到视图时,我们将在视图模型中表示实际的视图状态,并且我们的UI线程可以继续保持无垃圾状态。

public onBindViewHolder(Task.ViewHolder tvh, int position) {
    TaskViewModel taskViewModel = getItem(position);
    tvh.backgroundView.setColor(taskViewModel.getOverdueColor());
    tvh.dateTextView.setDate(taskViewModel.getDateDue());
}
Run Code Online (Sandbox Code Playgroud)