Paging Library 分頁加載庫
用於逐步從數據源加載信息,而不會耗費過多的設備資源或是等待太長的時間。
現有的分頁加載功能的優點 mix 缺陷:
CursorAdapter ,使得從數據庫加載數據到ListVIew變得非常容易。
但是這是在主線程中查詢數據庫,並且分也的內容實用低效的Cursor返回。
更多使用CursorAdapter帶來的問題參考Large Database Queries on Android。
AsyncListUtils ,提供基於位置的 分頁加載到RecycleView中。
但是無法使用不基於位置 的分頁加載,而且強制把null 作為占位符
DataSource 數據源
根據想要訪問數據的方式,可以有兩種子類可供選擇:
KeyedDataSource用於加載從第N到N+1 條數據
TiledDataSource用於從任意位置的分頁數據
例如使用
Room persistence library就可以自動創建返回
TiledDataSource類型的數據:
@Query("select * from users WHERE age > :age order by name DESC, id ASC")
TiledDataSource<User> usersOlderThan(int age);
PagedList 定量數據
從上面DataSource 獲取指定數量的數據,並且可以制定預取多少數據。這樣可以最大程度減少加載數據的時間。
ps:這個類提供更新信息給其他類
比如RecyclerView.Adapter來更新 RecyclerView的UI。
PagedListAdapter 適配器
這個類是
RecyclerView.Adapter得到一個實現類,用於當數據加載完畢時,通知Recycle數據1已經到達可以進行加載顯示。Recycleview就可以把數據填充進行顯示操作。
PagedListProvider
從數據源中產生 LiveData<PagedList>。此外如果使用的是 Room persistence library,DAO還能使用 TiledDataSource生成 LivePagedListProvider。示例代碼:
@Query("SELECT * from users order WHERE age > :age order by name DESC, id ASC”)
public abstract LivePagedListProvider<Integer, User> usersOlderThan(int age);
Paging Library從后台線程獲取數據流,再在Ui線程中展示就是通過以上幾個重要類。
流程圖:
當新的item插入到數據庫,DataSource被更新,LivePagedListProvider在后台線程產生了新的PagedList

繼而,中間新生成的PagedList 在主線程中被發送到PagedListAdapter中,讓它使用后台線程DiffUtil計算新的List和原來的List的差距,
當差異比較完后,PagedListAdapter用
RecyclerView.Adapter.notifyItemInserted()來通知數據刷新。
實例代碼:
/**
* Dao數據庫操作
*/
@Dao
interface UserDao{
@Query("SELECT * FROM user ORDER BY lastName ASC”)
public abstractLivePagedListProvider<Integer, User>usersByLastName();
}
/**
* ViewModel 數據源
*/
class MyViewModel extends ViewModel{
public final LiveData<PagedList<User>> usersList ;//數據list
public MyViewModel(UserDao userDao) {
usersList =userDao.usersByLastName().create(
/* initial load position */ 0,
new PagedList.Config.Builder()
.setPageSize(50)
.setPrefetchDistance(50) .build());
}
}
/**
* View層的實現
* 初始化ViewModel、RecycleView並綁定PagedListAdapter
* 通過observe方法將ViewMode數據加載到數據List中
*/
class MyActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
RecyclerViewrecyclerView = findViewById(R.id.user_list);
UserAdapter<User> adapter= new UserAdapter();
viewModel.usersList.observe(this,
pagedList -> adapter.setList(pagedList));
recyclerView.setAdapter(adapter);
}
}
/**
* PagedListAdapter 適配器配置
* 覆寫onBindViewHolder()方法
* @param UserViewHolder
* @param position
*/
class UserAdapter extends PagedListAdapter<User, UserViewHolder> {
public UserAdapter() {
super(DIFF_CALLBACK);
}
@Override
public void onBindViewHolder(UserViewHolder holder, int position) {
User user = getItem(position); //通過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();
}
}
/**
* 后台線程DiffUtil類回調: 計算新的List和原來的List的差距
*/
public static final
DiffCallback<User> DIFF_CALLBACK = new DiffCallback<User>() {
@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);
}
}
}
PS.鑒於大家的都建議給一個整體框架的demo,這里可以提供一個更好的方案:
Google Android Architecture Components,這是Google官方提供的樣例可以用來參考。
系列文章列表: