Paging Library官网文档(译)

英文原文:https://developer.android.google.cn/topic/libraries/architecture/paging.html

paging library 可以让 app 进行大数据查询的时候,在不过多增加设备负担或者等待时间的情况下,让渐进的从数据源加载数据变得更加简单。

概览

许多app都要用到大数据的加载,但是在某个时刻却只需要加载这些数据的一小部分。一个app可能需要展示成千上万个item,但是一次可能只需要获得其中的十几个。如果处理不当的话,可能会加载并不需要的数据,给设备和网络造成负担。如果数据是存储在远程的话,还可能会使app变慢,浪费用户的流量套餐。

虽然现有的 Android API 允许内容的分页,但是都有明显的限制和缺陷:

新的paging library 解决了这些问题。这个库包含了一些可以简化数据请求过程的一些类。这些类还与目前的 architecture components 无缝对接,比如Room

Paging Library提供了如下类,以及一些额外的辅助类:

  • DataSource

  • 这个类用于定义分页数据源。根据获取数据的方式,可以继承它的两个子类之一:

    如果你使用 Room persistence library 来管理数据,那么DataSource类是可以自动为你生成的。比如,这里是一个返回 TiledDataSource 的查询:

     
      
    1. @Query("select * from users WHERE age > :age order by name DESC, id ASC")
    2. TiledDataSource<User> usersOlderThan(int age);
    • 如果你需要从 item N 的数据获得 item N+1,使用 KeyedDataSource 。比如,在一个评论app中,要获取连续的评论,你可能需要传递其中一条评论的id来获得下一条评论。

    • 如果你需要从数据存储中获取任意位置开始的分页数据,使用TiledDataSource。这个类支持从任意位置开始请求一段数据,比如“返回从1200开始的20条数据”。

  • PagedList

  • 这个类从 DataSource加载数据。你可以设置一次加载多少数据,预取多少数据,以便最大程度的减少加载等待时间。它为其它类比如RecyclerView.Adapter提供更新信号,然你可以在在分页数据加载完成的时候更新RecyclerView的内容。

  • PagedListAdapter

  • 这个类是 RecyclerView.Adapter 的一种实现,它显示来自PagedList的数据。比如,当新的一页数据加载完成的时候,PagedListAdapter 通知 RecyclerView 新的数据到了;让 RecyclerView 把 placeholders 替换成真实的item,执行适当的动画。

    PagedListAdapter还使用一个后台线程计算从一个 PagedList 到下一个 PagedList 的变化(比如,当一个数据库的变更产生了一个新的PagedList ),并调用所需的 notifyItem…() 方法更新它的内容。然后 RecyclerView 执行必要的改变。比如,如果不同 PagedList 版本间的 一个 item 改变了位置,RecyclerView   对那个item执行动画,移动到新的位置。

  • LivePagedListProvider

  • 个类从你提供的 DataSource 中生成一个  LiveData<PagedList> 。此外,如果你使用 Room persistence library 来管理数据库,那么 DAO 可以为你生成 LivePagedListProvider 。比如下面的查询可以生成一个LivePagedListProvider:

     
      
    1. @Query("SELECT * from users order WHERE age > :age order by name DESC, id ASC")
    2. public abstract LivePagedListProvider<User> usersOlderThan(int age);

同时,Paging Library 的组建可以识别后台线程的数据流,并在UI线程显示。比如,数据库中插入一条item的时候, DataSource 将会刷新, LivePagedListProvider  在后台线程生成一个新的 PagedList 。

paging-threading.gif

图 1.   Paging Library 组建把绝大多数工作都放在了后台线程,因此不会加重UI负担 。

这个新生成的 PagedList  被发送到 UI 线程的PagedListAdapter  。然后 PagedListAdapter  在后台使用 DiffUtil 计算当前列表和新列表之间的差别。比较完成之后, PagedListAdapter 使用列表的差异信息去调用 RecyclerView.Adapter.notifyItemInserted() 通知插入了一条新的 item。

然后 RecyclerView 就知道了它只需绑定一条新的 item,并在屏幕上动画显示。

下面的代码示例显示了所有东西结合起来是如何工作的。当用户添加,删除或者修改数据库的时候,RecyclerView 自动高效的完成内容的更新。

 
  1. @Dao
  2. interface UserDao {
  3.     @Query("SELECT * FROM user ORDER BY lastName ASC")
  4.     public abstract LivePagedListProvider<Integer, User> usersByLastName();
  5. }
  6.  
  7. class MyViewModel extends ViewModel {
  8.     public final LiveData<PagedList<User>> usersList;
  9.     public MyViewModel(UserDao userDao) {
  10.         usersList = userDao.usersByLastName().create(
  11.                 new PagedList.Config.Builder()
  12.                         .setPageSize(50)
  13.                         .setPrefetchDistance(50)
  14.                         .build());
  15.     }
  16. }
  17.  
  18. class MyActivity extends AppCompatActivity {
  19.     @Override
  20.     public void onCreate(Bundle savedState) {
  21.         super.onCreate(savedState);
  22.         MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
  23.         RecyclerView recyclerView = findViewById(R.id.user_list);
  24.         UserAdapter<User> adapter = new UserAdapter();
  25.         viewModel.usersList.observe(this, pagedList -> adapter.setList(pagedList));
  26.         recyclerView.setAdapter(adapter);
  27.     }
  28. }
  29.  
  30. class UserAdapter extends PagedListAdapter<User, UserViewHolder> {
  31.     public UserAdapter() {
  32.         super(User.DIFF_CALLBACK);
  33.     }
  34.     @Override
  35.     public void onBindViewHolder(UserViewHolder holder, int position) {
  36.         User user = getItem(position);
  37.         if (user != null) {
  38.             holder.bindTo(user);
  39.         } else {
  40.             // Null defines a placeholder item - PagedListAdapter will automatically invalidate
  41.             // this row when the actual object is loaded from the database
  42.             holder.clear();
  43.         }
  44.     }
  45. }
  46.  
  47. @Entity
  48. class User {
  49.      // ... simple POJO code omitted ...
  50.  
  51.      public static final DiffCallback<User> DIFF_CALLBACK = new DiffCallback<Customer>() {
  52.          @Override
  53.          public boolean areItemsTheSame(
  54.                  @NonNull User oldUser, @NonNull User newUser) {
  55.              // User properties may have changed if reloaded from the DB, but ID is fixed
  56.              return oldUser.getId() == newUser.getId();
  57.          }
  58.          @Override
  59.          public boolean areContentsTheSame(
  60.                  @NonNull User oldUser, @NonNull User newUser) {
  61.              // NOTE: if you use equals, your object must properly override Object#equals()
  62.              // Incorrectly returning false here will result in too many animations.
  63.              return oldUser.equals(newUser);
  64.          }
  65.      }
  66. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值