分页库属于架构组件(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>