其實(shí)很多這種文章了的榛,但是很多都是Kotlin甚至都是一些理論琼了?還有一些是用VM模式(比如官方)。作為老骨頭,我們來看看Java最基礎(chǔ)版的雕薪。
我的主張是:先給我看代碼昧诱,我再考慮后面的。
2019-08-08更新
GoogleSamples有完整的Demo:PagingWithNetworkSample
簡單說下吧所袁,這個(gè)Demo比較完善盏档,但是我覺得不夠精簡。等我空了再重新分析整理一份燥爷,不過我這個(gè)老骨頭也已經(jīng)轉(zhuǎn)kotlin了蜈亩,以后的代碼也分享為kotlin了。
Paging的功能無非是控制頁面的加載過程(什么時(shí)候加載上一頁/下一頁前翎?)稚配,優(yōu)點(diǎn)自行搜索引擎。
時(shí)間倉促港华,先直接上代碼了道川。后面再來完善文章:
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 構(gòu)建本地模擬數(shù)據(jù)
1.1 模擬實(shí)體: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 模擬數(shù)據(jù)倉庫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
的數(shù)據(jù)源類 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) {
//模擬網(wǎng)絡(luò)調(diào)用耗時(shí)操作
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) {
//模擬網(wǎng)絡(luò)調(diào)用耗時(shí)操作
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
的數(shù)據(jù)工廠類 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);
}
}
4 DiffUtil.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)//設(shè)置首次加載的數(shù)量;
.setPageSize(15)//設(shè)置每一頁加載的數(shù)量苹丸;
.setMaxSize(15 + 2 * 3)
.setPrefetchDistance(3)//設(shè)置距離最后還有多少個(gè)item時(shí)愤惰,即自動(dòng)加載下一頁的數(shù)據(jù)苇经;
.setEnablePlaceholders(true)//表示是否設(shè)置null占位符赘理;
.build();
CustomRepository repository = new CustomRepository();
CustomPageDataSourceFactory factory = new CustomPageDataSourceFactory(repository);
LiveData<PagedList<StudentModel>> liveData = new LivePagedListBuilder<>(factory, config).build();
//這里的this是LifecycleOwner接口,而我們常用的AppCompatActivity已經(jīng)實(shí)現(xiàn)啦
liveData.observe(this, studentAdapter::submitList);
}
以上代碼只需要?jiǎng)?chuàng)建一個(gè)Activity
和對應(yīng)的Adapter
所需的item_test.xml
扇单,然后把上面的類全部copy到Activity
作為內(nèi)部類就可以直接跑起來了商模。當(dāng)然,Activity
里需要一個(gè)裝有RecyclerView
的activity_main.xml
蜘澜。施流。。