Android Jetpack组件之Paging Library使用篇
PS:做好当下,任何多余的思考和焦虑都是一种负担。
今天继续 Android Jetpack 组件的学习,同系列文章如下:
本文主要介绍 Paging Library 库的使用,由于微信公众号字数的限制,其源码解析将在下篇介绍,Paging Library 组件是 Android Jetpack 的一部分,是 Google 推出的官方分页组件,如果项目中使用了 Google 新推出的官方架构组件,如 LiveData、Lifecycle、ViewModel 等,就可以尝试将该分页组件引入自己的项目,它的优点是无痕加载更多数据,一定程度上提高用户体验。
简述一下使用 pageing 组件分页加载数据的过程,DataSource 负责从网络或数据库加载数据,将数据存储在 PagedList 中,使用 submitList 提交数据到 PagedListAdapter,当数据发生变化时会在后台线程中计算数据差异,最后 PagedListAdapter 通知 RecyclerView 更新数据。
准备数据
引入Paging Library组件
自定义DataSource
配置分页参数
加载显示数据
测试效果
准备数据
这里使用干货集中营的开源 Api 来进行测试,具体如下:
public interface CommonAPI {
// 这里使用干货集中营开源API:http://gank.io/api/search/query/listview/category/Android/count/10/page/1
("api/search/query/listview/category/Android/count/8/page/{page}")
Call<List<DataBean.ResultsBean>> getArticleList1( ("page") int page);
}
引入Paging Library组件
引入 Paging Library 库如下:
def paging_version = "2.1.0"
// androidx
implementation "androidx.paging:paging-runtime:$paging_version"
// 老版本 (page library 2.0.0-rc01)
implementation "android.arch.paging:runtime:$paging_version"
这里使用的是 androidx 最新版本。
自定义DataSource
自定义 DataSource 加载数据,这里加载的网络数据,使用 PageKeyedDataSource 更合适,继承 PageKeyedDataSource 自定义 DataSource 如下:
// 自定义DataSource
public class MDataSource extends PageKeyedDataSource<String, DataBean.ResultsBean> {
private static final String TAG = MDataSource.class.getSimpleName();
private int mPage = 1;
public MDataSource() {
}
// 初始化
public void loadInitial(@NonNull LoadInitialParams<String> params,
@NonNull final LoadInitialCallback<String, DataBean.ResultsBean> callback) {
Log.i(TAG, "--loadInitial-->");
CommonAPI api = RetrofitApi.getInstance().mRetrofit.create(CommonAPI.class);
Call<List<DataBean.ResultsBean>> call = api.getArticleList1(mPage);
call.enqueue(new Callback<List<DataBean.ResultsBean>>() {
public void onResponse(Call<List<DataBean.ResultsBean>> call, Response<List<DataBean.ResultsBean>> response) {
Log.i(TAG, "--onResponse-->" + response.toString());
if (response.isSuccessful() && response.code() == 200) {
List<DataBean.ResultsBean> data = response.body();
callback.onResult(data, "before", "after");
}
}
public void onFailure(Call<List<DataBean.ResultsBean>> call, Throwable t) {
Log.i(TAG, "--onFailure-->" + t.getMessage());
}
});
}
// 加载上一页
public void loadBefore(@NonNull LoadParams<String> params,
@NonNull LoadCallback<String, DataBean.ResultsBean> callback) {
Log.i(TAG, "--loadBefore-->" + params.key);
}
// 加载下一页
public void loadAfter(@NonNull final LoadParams<String> params,
@NonNull final LoadCallback<String, DataBean.ResultsBean> callback) {
Log.i(TAG, "--loadAfter-->" + params.key);
mPage++;
CommonAPI api = RetrofitApi.getInstance().mRetrofit.create(CommonAPI.class);
Call<List<DataBean.ResultsBean>> call = api.getArticleList1(mPage);
call.enqueue(new Callback<List<DataBean.ResultsBean>>() {
public void onResponse(Call<List<DataBean.ResultsBean>> call, Response<List<DataBean.ResultsBean>> response) {
Log.i(TAG, "--onResponse-->" + response.toString());
if (response.isSuccessful() && response.code() == 200) {
List<DataBean.ResultsBean> data = response.body();
callback.onResult(data, params.key);
}
}
public void onFailure(Call<List<DataBean.ResultsBean>> call, Throwable t) {
Log.i(TAG, "--onFailure-->" + t.getMessage());
}
});
}
}
很简单没有什么多余的东西,细节可以参考后文中的源码解析,创建一个工厂方便数据变化是创建新的 DataSource 如下:
// MDataSource创建工厂
public class MDataSourceFactory extends DataSource.Factory<String, DataBean.ResultsBean> {
public MDataSourceFactory() {
}
public DataSource<String, DataBean.ResultsBean> create() {
MDataSource mDataSource = new MDataSource();
return mDataSource;
}
}
配置分页参数
在 ViewModel 中创建 PagedList.Config 并进行分页参数配置,创建 DataSource 工厂对象,最终生成支持分页的 LiveData 数据,具体参考如下:
// ViewModel
public class MViewModel extends ViewModel {
private int pageSize = 20;
// PagedList配置
private PagedList.Config config = new PagedList.Config.Builder()
.setInitialLoadSizeHint(pageSize)//设置首次加载的数量
.setPageSize(pageSize)//设置每页加载的数量
.setPrefetchDistance(2)//设置距离每页最后数据项来时预加载下一页数据
.setEnablePlaceholders(false)//设置是否启用UI占用符
.build();
// DataSource.Factory
private DataSource.Factory<String,DataBean.ResultsBean> factory = new MDataSourceFactory();
// LiveData
private LiveData<PagedList<DataBean.ResultsBean>> mPagedList = new LivePagedListBuilder<>(factory, config)
.build();
public LiveData<PagedList<DataBean.ResultsBean>> getPagedList() {
return mPagedList;
}
}
加载显示数据
这里使用 LiveData 监听加载的数据,然后使用 sumbitList 将数据提交给 PagedListAdapter,会在后台线程中对比新旧数据的差异,最后更新 RecyclerView ,具体如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private RecyclerView mRecyclerView;
private ArticleAdapter mAdapter;
private MViewModel mViewModel;
private static DiffUtil.ItemCallback<DataBean.ResultsBean> itemCallback = new DiffUtil.ItemCallback<DataBean.ResultsBean>() {
public boolean areItemsTheSame(@NonNull DataBean.ResultsBean oldItem, @NonNull DataBean.ResultsBean newItem) {
return oldItem.getGanhuo_id() == newItem.getGanhuo_id();
}
public boolean areContentsTheSame(@NonNull DataBean.ResultsBean oldItem, @NonNull DataBean.ResultsBean newItem) {
return oldItem.equals(newItem);
}
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.rvData);
mAdapter = new ArticleAdapter(itemCallback);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(mAdapter);
ViewModelProvider mViewModelProvider = new ViewModelProvider(this,
new ViewModelProvider.AndroidViewModelFactory(getApplication()));
mViewModel = mViewModelProvider.get(MViewModel.class);
}
public void getData(View view) {
mViewModel.getPagedList().observe(this, new Observer<PagedList<DataBean.ResultsBean>>() {
public void onChanged(PagedList<DataBean.ResultsBean> dataBeans) {
Log.i(TAG, "--onChanged-->");
mAdapter.submitList(dataBeans);
}
});
}
}
测试效果
如上就是 Paging Library 库的使用方式,介于微信公众号文章字数限制,其源码解析将在下篇文章中介绍,可在公众号回复【加群】要你进微信交流群。
推荐阅读: