Paging Library

作者: 慕涵盛华 | 来源:发表于2017-09-21 17:42 被阅读218次

    英文原文:https://developer.android.com/topic/libraries/architecture/paging.html#classes

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

    概览

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

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

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

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

    • DataSource

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

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

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

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

    • PagedList

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

    • LivePagedListProvider

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

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

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

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

    @Dao
    interface UserDao {
    @Query("SELECT * FROM user ORDER BY lastName ASC")
    public abstract LivePagedListProvider<Integer, User> usersByLastName();
    }
    
    class MyViewModel extends ViewModel {
        public final LiveData<PagedList<User>> usersList;
        public MyViewModel(UserDao userDao) {
            usersList = userDao.usersByLastName().create(
                    new PagedList.Config.Builder()
                            .setPageSize(50)
                            .setPrefetchDistance(50)
                            .build());
        }
    }
    
    class MyActivity extends AppCompatActivity {
        @Override
        public void onCreate(Bundle savedState) {
            super.onCreate(savedState);
            MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
            RecyclerView recyclerView = findViewById(R.id.user_list);
            UserAdapter<User> adapter = new UserAdapter();
            viewModel.usersList.observe(this, pagedList -> adapter.setList(pagedList));
            recyclerView.setAdapter(adapter);
        }
    }
    
    class UserAdapter extends PagedListAdapter<User, UserViewHolder> {
        public UserAdapter() {
            super(User.DIFF_CALLBACK);
        }
        @Override
        public void onBindViewHolder(UserViewHolder holder, int position) {
            User user = getItem(position);
            if (user != null) {
                holder.bindTo(user);
            } else {
                // Null defines a placeholder item - PagedListAdapter will automatically invalidate
                // this row when the actual object is loaded from the database
                holder.clear();
            }
        }
    }
    
    @Entity
    class User {
         // ... simple POJO code omitted ...
    
         public static final DiffCallback<User> DIFF_CALLBACK = new DiffCallback<Customer>() {
             @Override
             public boolean areItemsTheSame(
                     @NonNull User oldUser, @NonNull User newUser) {
                 // User properties may have changed if reloaded from the DB, but ID is fixed
                 return oldUser.getId() == newUser.getId();
             }
             @Override
             public boolean areContentsTheSame(
                     @NonNull User oldUser, @NonNull User newUser) {
                 // NOTE: if you use equals, your object must properly override Object#equals()
                 // Incorrectly returning false here will result in too many animations.
                 return oldUser.equals(newUser);
             }
         }
    }
    

    关注微信公众号获取更多相关资源

    Android小先生

    相关文章

      网友评论

        本文标题:Paging Library

        本文链接:https://www.haomeiwen.com/subject/lsvnsxtx.html