优化RecyclerView / ListView

时间:2015-01-16 22:12:26

标签: android android-listview android-recyclerview

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

谢谢!

1 个答案:

答案 0 :(得分:4)

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

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

由于onBindViewHolder()方法中的所有这些工作都是在UI线程上完成的,因此在绑定之前卸载任何其他工作或卸载到anthoer线程有助于列出视图性能。

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

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

    // getters and setters here
}

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

onBindViewHolder()中有两件事要做,因为每一行都会呈现在屏幕上:

  • 您需要有条件地检查每个日期并将其与今天的日期进行比较
  • 您需要应用日期格式化程序才能在所需规范中查看日期:

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);
    }
}

在上文中,对于每个渲染的行,正在进行日期比较。当我们参与其中时,我们甚至冒昧地将今天的日期变为常数 - 对象创建可能是您在onBindViewHolder()中可以做的最昂贵的事情之一,因此任何优化都会受到赞赏。此外,Task对象中传递的日期格式不正确,因此也可以即时格式化。

虽然这个示例是 trivial ,但这可以快速演示停止滚动到爬网的列表视图。更好的方法是传递一个中间对象,例如代表视图状态的视图模型而不是实际的业务模型。

我们不是将Task作为模型传递给适配器,而是创建一个名为TaskViewModel的中间模型,创建并设置为适配器。现在,在将任何信息发送到适配器之前,所有工作都在应用任何视图渲染之前完成。这需要在将数据发送到RecyclerView之前更长的初始化时间,但需要更好地权衡列表视图的性能。

此视图模型可能是:

public class TaskViewModel {
    int overdueColor;
    String dateDue;
}

现在,当负责将数据绑定到视图时,我们将在视图模型中表示实际的视图状态,并且我们的UI线程可以继续使用。

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