分页库属于架构组件(Architecture Components)的一部分,配合RecyclerView使用,主要用来实现无感分页加载。
官方文档链接为:https://developer.android.google.cn/topic/libraries/architecture/paging
本文参照官方文档来做一个简单的实现,主要分以下几步:
1、导库:
def support_version = '28.0.0-rc01'
implementation "com.android.support:appcompat-v7:$support_version"
implementation "com.android.support:recyclerview-v7:$support_version"
implementation "android.arch.paging:runtime:1.0.1"
2、创建数据实体:
public class DataBean {
public int id;
public String content;
public int getId() {
return id;
}
public boolean equals(DataBean o) {
return TextUtils.equals(content, o.content);
}
}
3、创建分页适配器:
//类似于RecyclerView.Adapter的写法,只不多了些一次数据比较DiffUtil.ItemCallback
public class ConcertAdapter extends PagedListAdapter<DataBean, ConcertAdapter.ConcertViewHolder> {
private Context context;
public ConcertAdapter(Context context) {
super(DIFF_CALLBACK);
this.context = context;
}
@NonNull
@Override
public ConcertViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, viewGroup, false);
return new ConcertViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ConcertViewHolder concertViewHolder, int position) {
DataBean dataBean = getItem(position);
if (dataBean == null) return;
concertViewHolder.textView.setText(dataBean.content);
}
class ConcertViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ConcertViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(android.R.id.text1);
}
}
private static DiffUtil.ItemCallback<DataBean> DIFF_CALLBACK =
new DiffUtil.ItemCallback<DataBean>() {
@Override
public boolean areItemsTheSame(DataBean oldItem, DataBean newItem) {
return oldItem.getId() == newItem.getId();
}
@Override
public boolean areContentsTheSame(DataBean oldItem, @NonNull DataBean newItem) {
return oldItem.equals(newItem);
}
};
}
4、创建模拟加载本地数据的数据源DataSource:
public class LocalTestDataSource extends PositionalDataSource<DataBean> {
@Override
public void loadInitial(@NonNull LoadInitialParams params,
final @NonNull LoadInitialCallback<DataBean> callback) {
final int startPosition = 0;
List<DataBean> list = buildDataList(startPosition, params.requestedLoadSize);
//将数据回调
callback.onResult(list, 0);
}
@Override
public void loadRange(@NonNull final LoadRangeParams params,
@NonNull final LoadRangeCallback<DataBean> callback) {
List<DataBean> list = buildDataList(params.startPosition, params.loadSize);
callback.onResult(list);
}
private List<DataBean> buildDataList(int startPosition, int loadSize) {
List<DataBean> list = new ArrayList<>();
DataBean bean;
for (int i = startPosition; i < startPosition + loadSize; i++) {
bean = new DataBean();
bean.id = i;
bean.content = String.format(Locale.getDefault(), "第%d条数据", i + 1);
list.add(bean);
}
return list;
}
}
5、创建数据源工厂,其中一个的作用是用来生产第4步的数据源:
public class DataSourceFactory
extends DataSource.Factory<Integer, DataBean> {
private MutableLiveData<LocalTestDataSource> mSourceLiveData =
new MutableLiveData<>();
@Override
public DataSource<Integer, DataBean> create() {
LocalTestDataSource source = new LocalTestDataSource();
mSourceLiveData.postValue(source);
return source;
}
}
6、创建ViewModel,主要作用是得到与第4步数据源(DataSource)相关联的LiveData:
public class ConcertViewModel extends ViewModel {
private Executor myExecutor = Executors.newSingleThreadExecutor();
private PagedList.Config myPagingConfig = new PagedList.Config.Builder()
.setInitialLoadSizeHint(20)
.setPageSize(10)
.setPrefetchDistance(30)
.setEnablePlaceholders(false)
.build();
private DataSource.Factory<Integer, DataBean> myConcertDataSource =
new DataSourceFactory();
public LiveData<PagedList<DataBean>> getConcertList() {
return concertList;
}
private LiveData<PagedList<DataBean>> concertList =
new LivePagedListBuilder<>(myConcertDataSource, myPagingConfig)
.setFetchExecutor(myExecutor)
.build();
//用于刷新数据
public void invalidateDataSource() {
PagedList<DataBean> pagedList = concertList.getValue();
if (pagedList != null)
pagedList.getDataSource().invalidate();
}
}
7、在Activity里使用:
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private SwipeRefreshLayout swipeRefreshLayout;
private ConcertAdapter mAdapter;
private ConcertViewModel mViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new ConcertAdapter(this);
recyclerView.setAdapter(mAdapter);
ViewModelProvider provider = new ViewModelProvider(this,
new ViewModelProvider.AndroidViewModelFactory(getApplication()));
mViewModel = provider.get(ConcertViewModel.class);
//LiveData关联到mAdapter,并与Activity相关联
mViewModel.getConcertList().observe(this, new Observer<PagedList<DataBean>>() {
@Override
public void onChanged(@Nullable PagedList<DataBean> dataBeans) {
mAdapter.submitList(mViewModel.getConcertList().getValue());
}
});
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
//刷新数据
mViewModel.invalidateDataSource();
swipeRefreshLayout.setRefreshing(false);
}
});
}
}
相关联的布局文件R.layout.activity_main为:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>