Android Paging瞭解一下?
其實很多這種文章了,但是很多都是Kotlin甚至都是一些理論?還有一些是用VM模式(比如ofollow,noindex">官方 )。作為老骨頭,我們來看看Java最基礎版的。
我的主張是:先給我看程式碼,我再考慮後面的。
Paging的功能無非是控制頁面的載入過程(什麼時候載入上一頁/下一頁?),優點自行搜尋引擎。
時間倉促,先直接上程式碼了。後面再來完善文章:
0 引入paging庫
def pagingCommonVersion = '2.0.0-rc01' def pagingNewestVersion = '2.1.0-beta01' dependencies { api 'androidx.recyclerview:recyclerview:1.0.0' api "androidx.paging:paging-common:$pagingCommonVersion" api "androidx.paging:paging-runtime:$pagingNewestVersion" }
1 構建本地模擬資料
1.1 模擬實體:StudentModel
class StudentModel { int id; String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
1.2 模擬資料倉庫CustomRepository
class CustomRepository { List<StudentModel> studentModels = new ArrayList<>(); CustomRepository() { for (int i = 0; i < 100; i++) { StudentModel studentModel = new StudentModel(); studentModel.setId(i); studentModel.setName("name" + i); studentModels.add(studentModel); } } List<StudentModel> getStudentsInit(@IntRange(from = 0) int initSize) { return studentModels.subList(0, initSize);//包含~不包含 } List<StudentModel> getStudentsByRange(@IntRange(from = 0) int from, int to) { return studentModels.subList(from, to); } List<StudentModel> getStudentsByPage(@IntRange(from = 0) int page, int size) { int totalPage = 0; if (studentModels.size() % size == 0) { totalPage = studentModels.size() / size; } else { totalPage = studentModels.size() / size + 1; } if (page >= totalPage || page < 0) { return null; } if (page == totalPage - 1) { return studentModels.subList(page * size, studentModels.size()); } return studentModels.subList(page * size, (page + 1) * size); } }
2 繼承於PageKeyedDataSource
的資料來源類CustomPageDataSource
class CustomPageDataSource extends PageKeyedDataSource<Integer, StudentModel> { private CustomRepository mCustomRepository; CustomPageDataSource(CustomRepository customRepository) { this.mCustomRepository = customRepository; } @Override public void loadInitial(@NonNull LoadInitialParams<Integer> params, @NonNull LoadInitialCallback<Integer, StudentModel> callback) { List<StudentModel> studentModels = mCustomRepository.getStudentsInit(params.requestedLoadSize); callback.onResult(studentModels, null, 1); } @Override public void loadBefore(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, StudentModel> callback) { //模擬網路呼叫耗時操作 new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } List<StudentModel> studentModels = mCustomRepository.getStudentsByPage(params.key, params.requestedLoadSize); callback.onResult(studentModels, params.key - 1); } }).start(); } @Override public void loadAfter(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, StudentModel> callback) { //模擬網路呼叫耗時操作 new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } List<StudentModel> studentModels = mCustomRepository.getStudentsByPage(params.key, params.requestedLoadSize); if (studentModels != null) { callback.onResult(studentModels, params.key + 1); } } }).start(); } }
3 繼承於DataSource.Factory
的資料工廠類CustomPageDataSourceFactory
class CustomPageDataSourceFactory extends DataSource.Factory<Integer, StudentModel> { private CustomRepository mCustomRepository; CustomPageDataSourceFactory(CustomRepository customRepository) { this.mCustomRepository = customRepository; } @NonNull @Override public DataSource<Integer, StudentModel> create() { return new CustomPageDataSource(mCustomRepository); } }
4DiffUtil.ItemCallback
private static DiffUtil.ItemCallback<StudentModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<StudentModel>() { // Concert details may have changed if reloaded from the database, // but ID is fixed. @Override public boolean areItemsTheSame(StudentModel oldConcert, StudentModel newConcert) { return oldConcert.getId() == newConcert.getId(); } @Override public boolean areContentsTheSame(StudentModel oldConcert, StudentModel newConcert) { return oldConcert.equals(newConcert); } };
5 繼承於PagedListAdapter
的StudentAdapter
public class StudentAdapter extends PagedListAdapter<StudentModel, StudentAdapter.CustomViewHolder> { protected StudentAdapter() { super(DIFF_CALLBACK); } @NonNull @Override public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new CustomViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_test, parent, false)); } @Override public void onBindViewHolder(@NonNull CustomViewHolder holder, int position) { StudentModel studentModel = getItem(position); holder.tvID.setText(String.valueOf(studentModel.getId())); holder.tvName.setText(studentModel.getName()); } class CustomViewHolder extends RecyclerView.ViewHolder { TextView tvID, tvName; public CustomViewHolder(@NonNull View itemView) { super(itemView); tvID = itemView.findViewById(R.id.tv_id); tvName = itemView.findViewById(R.id.tv_name); } } }
6 使用MainActivity
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(this)); StudentAdapter studentAdapter = new StudentAdapter(); recyclerView.setAdapter(studentAdapter); PagedList.Config config = new PagedList.Config.Builder() .setInitialLoadSizeHint(10)//設定首次載入的數量; .setPageSize(15)//設定每一頁載入的數量; .setMaxSize(15 + 2 * 3) .setPrefetchDistance(3)//設定距離最後還有多少個item時,即自動載入下一頁的資料; .setEnablePlaceholders(true)//表示是否設定null佔位符; .build(); CustomRepository repository = new CustomRepository(); CustomPageDataSourceFactory factory = new CustomPageDataSourceFactory(repository); LiveData<PagedList<StudentModel>> liveData = new LivePagedListBuilder<>(factory, config).build(); //這裡的this是LifecycleOwner介面,而我們常用的AppCompatActivity已經實現啦 liveData.observe(this, studentAdapter::submitList); }
以上程式碼只需要建立一個Activity
和對應的Adapter
所需的item_test.xml
,然後把上面的類全部copy到Activity
作為內部類就可以直接跑起來了
。當然,Activity
裡需要一個裝有RecyclerView
的activity_main.xml
。。。