Skip to content
panwj edited this page Jun 17, 2019 · 4 revisions

概览

    Paging配合RecyclerView更容易从数据源中高效优雅的加载所需数据,不会因为数据库数据量大而造成查询时间过长。
Paging库的优点:
1. 数据请求占用比较少的网络带宽和系统资源;
2. 在数据更新和刷新期间,app也能快速响应用户输入

库架构

库架构:分页库关键组件是PagedList类,该类异步加载app所需要的数据以及分页数据。这个类为app的其他架构组件提供了联系。分页库实现了观察者模式.

Data: 每个PagingList实例从DataSource为你的App提供最新的数据。数据流从你的app后台或者数据库流向PagingList对象。DataSource提供一个单一的元数据,Factory加载内容。 分页库支持支持很多app架构,包括独立数据库或者服务器网络数据。

UI: PagingList类和PagingListAdapter配合使用,加载items数据到RecyclerView中。这些类一起使用来获取和显示已经加载的数据,预加载以及观察数据变化并自动更新。

数据架构

支持的数据架构:仅从网络获取、仅从本地数据库获取、从网络和数据库同时获取

  1. 网络获取或本地数据库:都是异步实现数据加载 数据库获取时,观察数据库,数据库内容发生改变数据库就会pull一个新的PagedList。 RecyclerView加载本地数据,可以使用Room库。通过这种方式,当向数据库中添加、修改、删除数据,这些变化都会被观察到,从而触发UI自动刷新。 网络获取时,下拉刷新网络加载(后端不发送更新)时会pull一个新的PagedList并使旧的无效。从后台服务器获取,使用同步的Retrofit API加载网络数据到你的DataSource对象中。

  2. 网络和数据库同时获取 数据库是网络缓存的数据,ui从数据库加载数据,数据库没有在从网络获取,又在回调中请求网络,将获取到的数据插入数据库,ui订阅了数据库的更新,因此,新的数据会流向正在观察的ui,实现刷新。

    注意:分页库的DataSource对象不提供任何错误处理,因为不同app处理和展示错误的方式不同。如果一个错误发生,将错误传递给callback中,尝试后续重新请求

对比

当前实现分页加载的方法有两种,使用CursorAdapter;使用AsyncListUtil

  1. CursorAdapter 可以是ListView很容易的加载数据,但是他是运行在UI线程的,而且Cursor也会在页面上出现无效的现象。

  2. AsyncListUtil允许RecycleView基于position进行分页加载,但是不允许非position进行分页加载,在数据集中强制使用null作为修饰符。 Paging解决了这些问题。此库简化了请求数据的过程。

使用注意事项

  1. 在app Module的build.gradle中添加如下依赖:

`` dependencies { def paging_version = "1.0.0"

implementation "android.arch.paging:runtime:$paging_version"
// alternatively - without Android dependencies for testing
testImplementation "android.arch.paging:common:$paging_version"
    // optional - RxJava support, currently in release candidate
    implementation "android.arch.paging:rxjava2:1.0.0-rc1"
}
AndroidX(Android Jetpack)
dependencies {
    def paging_version = "2.0.0-beta01"
implementation "androidx.paging:paging-runtime:$paging_version"
// alternatively - without Android dependencies for testing
testImplementation "androidx.paging:paging-common:$paging_version"
    // optional - RxJava support
    implementation "androidx.paging:paging-rxjava2:$paging_version"
}
````java
  1. 在ui中实现占位: 在app获取到数据之前,如果想让ui显示列表,可以先像用户展示占位列表,默认情况下,placeHolder是开启的

占位有一下优点:

  1. 支持滚动条:PagingList提供了List item的数量给PagedListAdapter.这些信息允许Adapter绘制一个滚动条传达list的尺寸。当新的页数加载后,滚动条不会滚动,因为有的list没有改变尺寸。

  2. 没有加载Loading提示的必要:因为list尺寸已经知道了,没有必要告诉用户有更多的items正在被加载。placeholders已经传达了这些信息。

在使用占位支持之前,如下先决条件需要知道:

需要一个数据集大小是确定的:通过Room持久库获取的DataSource可以有效的确定它们的数量。如果你正在使用一个本地存储解决方案或者仅仅通过网路数据架构,那很可能无法确定你的数据集的数量。
需要Adapter触发未加载数据的加载:Adapter或者已存在的机制用于处理null items的情形。例如,当你bind数据到一个ViewHolder,你需要提供默认值给未加载的数据。
需要每个item有相同的view大小:如果对于社交网络更新(例如:聊天界面)item的大小依赖于内容。强烈建议你关掉placeholders功能。
  1. Paging配置可以通过如下属性设置完成:

`` a. Page size:每一页item数量。 b. Prefetch distance:预加载数量,通常是page size整数倍 c. Placeholder presence:是否启用占位功能。

PagedList.Config myPagingConfig = new PagedList.Config.Builder() .setPageSize(50) .setPrefetchDistance(150) .setEnablePlaceholders(true) .build();

DataSource.Factory<Integer, Concert> myConcertDataSource = concertDao.concertsByDate();

LiveData<PagedList<Concert>> concertList = new LivePagedListBuilder<>(myConcertDataSource, myPagingConfig) .setFetchExecutor(myExecutor) .build(); ````java

  1. 选择正确的数据源类型

    使用DataSource定义你需要提取分页的数据源。根据使用场景使用的不同使用它不同的子类,如下
    1. 使用PageKeyDataSource,让你加载的页面插入到下一个或者以前的key,例如:例如:你要从网络获取社交媒体的帖子,你就需要通过nextPage加载到后续的加载中。

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

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

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

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

PagedList数据加载机制:

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

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

Clone this wiki locally