当前位置:   article > 正文

Android官方分页组件介绍之Paging的使用详解_详细讲解一下 android paging 的使用方法

详细讲解一下 android paging 的使用方法

Paging 使您的应用程序更容易从数据源中逐渐加载所需的信息,不会因为数据库数据量大而造成查询时间过长。

概述

在我们的实际项目中有大量的数据,但是我们常常只需要向用户展示一小部分信息。一个应用中可能会有几千个item但是我们常常只需要显示十几个或者几十个。我们处理不当加载数据时可能会造成APP崩溃。如果数据被存储或与远程数据库同步,这也会减慢应用程序的速度,影响用户的体验。

尽管Android APIs可以实现分页加载,但是仍不够完美。

1.CursorAdapter 可以是ListView很容易的加载数据,但是他是运行在UI线程的,而且Cursor也会在页面上出现无效的现象,使用CursorAdapter还有更多的缺点,详细请查看博客

2.AsyncListUtil允许RecycleView基于position进行分页加载,但是不允许非position进行分页加载,在数据集中强制使用null作为修饰符。

Paging解决了这些问题。此库中的几个简化了请求数据的过程。这几个类还可以和组件化架构进行无缝对接。

功能

获取数据

使用DataSource定义你需要提取分页的数据源。根据使用场景使用的不同使用它不同的子类,如下

1.使用PageKeyDataSource,让你加载的页面插入到下一个或者以前的key,例如:例如:你要从网络获取社交媒体的帖子,你就需要通过nextPage加载到后续的加载中。

2.使用ItemKeyDataSource,如果你需要让使用的数据的item从N条增加到N+1条请使用。例如:你需要从嵌套评论中获取一条评论,需要通过一条评论的ID获取下一条评论的内容。

3.PositionalDataSource,如果你需要从事数据存储的任意位置来获取数据页,此类支持你从任意你选择的位置开始请求item的数据集。比如从第1200条返回20条item。

如果使用Room来管理数据,就要使用DataSource.Factory来初始化PositionalDataSource。如下:

  1. @Query("select * from users WHERE age > :age order by name DESC, id ASC")
  2. DataSource.Factory<Integer, User> usersOlderThan(int age);

将数据加载进内存

PagedList类加载的数据来自于DataSource。你可以配置一次加载多少数据,可以预先获取多少数据,尽量减少加载数据的时间。此类也可以向其他类提供数据更新的信号,比如:RecycleView.Adapter一样,为RecycleView页允许数据加载。

PagedList在架构使用中有如下几种方式

将数据显示到UI上

PagedListAdapter类实现自RecycleView.Adapter,并且从PagedList中加载数据。例如:当一个新的页面被加载PagedListAdapter就会发信号通知RecycleView数据已经到了,然后RecycleView就是显示和数据量相等的item,并执行适当的动画。

PagedListAdapter对于来自一个PagedList的下一条数据会在后台线程进行计算。(例如:将数据库的新数据更新到PagedList中),调用notifyItem..()方法更新需要的数据列表的内容。然后RecycleView再执行必要的更改。例如:item的position的顺序的改变。

观察数据的更新

Paging使用下列类来构造PagedList容器实时更新:

1.LivePageListBuilder此类是从DataSource.Factory构建LiveData<PagedList>。如果使用Room来管理数据库,Dao可以生成DataSource.Factory,使用PositionnalDataSource,如下:

This class generates a LiveData<PagedList> from theDataSource.Factory you provide. If you use the Room persistence libraryto manage your database, the DAO can generate the DataSource.Factoryfor you, using PositionalDataSource, as shown in the following example:

  1. LiveData<PagedList<Item>> pagedItems =
  2. LivePagedListBuilder(myDataSource, /* page size */ 50)
  3. .setFetchExecutor(myNetworkExecutor)
  4. .build();

2.RXPagedListBuilder此类支持RXJava。使用此类实现PagedList来构造Flowable和Observable如下所示:

  1. Flowable<PagedList<Item>> pagedItems =
  2. RxPagedListBuilder(myDataSource, /* page size */ 50)
  3. .setFetchScheduler(myNetworkScheduler)
  4. .buildFlowable(BackpressureStrategy.LATEST);

创建数据流

Figure 1. Paging的数据流是在后台线程生产,在UI线程中显示。例如:当一条新的item插入到数据库中,DataSource被初始化,LiveData<PagedList>或者Flowable<PagedList>后台线程就会创建一个新的PagedList


Paging在后台线程中完成大部分工作,所以不会给主线程带来负担。

这个新建的PagedList会被发送到UI线程的PagedListAdapter。PagedListAdapter使用DiffUtil在对比现在的表单和新建表单的差异。当对比结束,PagedListAdapter通过调用RecycleView.Adapter.notifyItemInserted()将新的item插入到适当的位置。RecycleView就会知道他需要绑定一个新的item,并将其显示。

数据库案例

1.>LiveDate使用

使用RecycleView 高效的进行数据库的增删改查。

  1. @Dao
  2. interface UserDao {
  3. // The Integer type parameter tells Room to use a PositionalDataSource
  4. // object, with position-based loading under the hood.
  5. @Query("SELECT * FROM user ORDER BY lastName ASC")
  6. public abstract DataSource.Factory<Integer, User> usersByLastName();
  7. }
  8. class MyViewModel extends ViewModel {
  9. public final LiveData<PagedList<User>> usersList;
  10. public MyViewModel(UserDao userDao) {
  11. usersList = new LivePagedListBuilder<>(
  12. userDao.usersByLastName(), /* page size */ 20).build();
  13. }
  14. }
  15. class MyActivity extends AppCompatActivity {
  16. private UserAdapter<User> mAdapter;
  17. @Override
  18. public void onCreate(Bundle savedState) {
  19. super.onCreate(savedState);
  20. MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
  21. RecyclerView recyclerView = findViewById(R.id.user_list);
  22. mAdapter = new UserAdapter();
  23. viewModel.usersList.observe(this, pagedList ->
  24. mAdapter.submitList(pagedList));
  25. recyclerView.setAdapter(mAdapter);
  26. }
  27. }
  28. class UserAdapter extends PagedListAdapter<User, UserViewHolder> {
  29. public UserAdapter() {
  30. super(DIFF_CALLBACK);
  31. }
  32. @Override
  33. public void onBindViewHolder(UserViewHolder holder, int position) {
  34. User user = getItem(position);
  35. if (user != null) {
  36. holder.bindTo(user);
  37. } else {
  38. // Null defines a placeholder item - PagedListAdapter will automatically invalidate
  39. // this row when the actual object is loaded from the database
  40. holder.clear();
  41. }
  42. }
  43. public static final DiffUtil.ItemCallback<User> DIFF_CALLBACK =
  44. new DiffUtil.ItemCallback<User>() {
  45. @Override
  46. public boolean areItemsTheSame(@NonNull User oldUser, @NonNull User newUser) {
  47. // User properties may have changed if reloaded from the DB, but ID is fixed
  48. return oldUser.getId() == newUser.getId();
  49. }
  50. @Override
  51. public boolean areContentsTheSame(@NonNull User oldUser, @NonNull User newUser) {
  52. // NOTE: if you use equals, your object must properly override Object#equals()
  53. // Incorrectly returning false here will result in too many animations.
  54. return oldUser.equals(newUser);
  55. }
  56. }
  57. }

2.>RXJava使用

如果使用RXJava需要创建Obervabl或者Flowable对象:

  1. class MyViewModel extends ViewModel {
  2. public final Flowable<PagedList<User>> usersList;
  3. public MyViewModel(UserDao userDao) {
  4. usersList = new RxPagedListBuilder<>(userDao.usersByLastName(),
  5. /* page size */ 50).buildFlowable(BackpressureStrategy.LATEST);
  6. }
  7. }

观察数据的开始和停止使用如下:

  1. class MyActivity extends AppCompatActivity {
  2. private UserAdapter<User> mAdapter;
  3. private final CompositeDisposable mDisposable = new CompositeDisposable();
  4. @Override
  5. public void onCreate(Bundle savedState) {
  6. super.onCreate(savedState);
  7. MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
  8. RecyclerView recyclerView = findViewById(R.id.user_list);
  9. mAdapter = new UserAdapter();
  10. recyclerView.setAdapter(mAdapter);
  11. }
  12. @Override
  13. protected void onStart() {
  14. super.onStart();
  15. myDisposable.add(mViewModel.usersList.subscribe(flowableList ->
  16. mAdapter.submitList(flowableList)));
  17. }
  18. @Override
  19. protected void onStop() {
  20. super.onStop();
  21. mDisposable.clear();
  22. }
  23. }

UserDao和UserAdapter的代码对于基于rxjava2的解决方案是一样的,因为它们是基于live数据的解决方案

选择数据加载架构

使用Paging有两个主要的分页数据方式。

网络或者数据库

首先页面加载的数据来自于网络和数据库二者之一。如上所示,使用LiveData<PagedList>将数据加载进UI中。需要指定一个元数据传递DataSource.Factory至LivePagedListBuilder。


Figure 2.DataSource提供一个单一的元数据,Factory加载内容。

观察一个数据库时,数据库内容发生改变数据库就会pull一个新的PagedList。

下拉刷新加载网络加载时(后端不发送更新)会pull一个新的PagedList并使旧的无效。

以上这两种方式的数据都是异步加载的。

怎么通过实现DataSource.Factory+Retrofit 网络加载处理下拉刷新,网络异常,和重试PagingWithNetworkSample

网络和数据库

实例二,加载本地存储页,它本身会从网络加载附加数据。这通常是为了最小化网络负载并提供更好的低连接性体验——数据库被用作存储在后端的数据的缓存。

如图,LiveData<PagedList>从数据库获取一个连接,然后通过LivePagedListBuilder至BoundaryCallback,最后观察到数据完成的信号。

Figure 3.数据库时网络数据的缓存,UI是从数据库中加载,如果数据库中没有再从网络中获取。

然后在回调中请求网络,将这些数据直接储存在数据库中。UI订阅了数据库的更新,因此,新的数据会自动流向正在观察的UI。

怎么通过实现DataSource.Factory+Retrofit 网络加载处理下拉刷新,网络异常,和重试PagingWithNetworkSample

官网地址:https://developer.android.google.cn/topic/libraries/architecture/paging

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号