第五章:paging 使用
public abstract PagedListAdapter getAdapter();
}
创建 ViewModel 处理类
package com.paging.study.viewmodel;
import android.annotation.SuppressLint;
import android.app.Application;
import android.util.ArrayMap;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.arch.core.executor.ArchTaskExecutor;
import androidx.paging.DataSource;
import androidx.paging.ItemKeyedDataSource;
import com.paging.study.bean.Teacher;
import com.paging.study.http.PagingHttpCallback;
import com.paging.study.http.PagingHttpClient;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
public class BlankViewModel extends AbsViewModel<Teacher.RecordsBean> {
public BlankViewModel(@NonNull Application application) {
super(application);
}
/**
同步位置标记,防止 paging 和我们自己的分页重复
*/
private AtomicBoolean loadAfter = new AtomicBoolean();
@Override
protected DataSource createDataSource() {
return new TeacherDataSource();
}
/**
DataSource<Key,Value>数据源:
key 对应加载数据的条件信息,value 对应数据实体类
<p>
PageKeyedDataSource<Key,Value>:
适用于目标数据根据页面信息请求数据的场景
<p>
ItemKeyedDataSource<Key,Value>:
适用于目标数据的加载依赖特定 item 的信息
<p>
PositionalDataSource<Key,Value>:
适用于目标数据总数固定,通过特定的位置加载数据
*/
class TeacherDataSource extends ItemKeyedDataSource<String, Teacher.RecordsBean> {
@Override
public void loadInitial(@NonNull LoadInitialParams<String> params,
@NonNull LoadInitialCallback<Teacher.RecordsBean> callback) {
pageCurrent = 1;
//加载初始化数据的
loadData("0", callback);
}
@Override
public void loadAfter(@NonNull LoadParams<String> params, @NonNull LoadCallback<Teacher.RecordsBean> callback) {
//向后加载分页数据的
loadData(params.key, callback);
}
@Override
public void loadBefore(@NonNull LoadParams<String> params, @NonNull LoadCallback<Teacher.RecordsBean> callback) {
callback.onResult(Collections.<Teacher.RecordsBean>emptyList());
//能够向前加载数据的(例如初始化进入加载的是第 3 页,向上翻的时候加载第二第一页)
}
@NonNull
@Override
public String getKey(@NonNull Teacher.RecordsBean item) {
//通过最后一条 item 的信息加载数据
return item.getPaintingId();
}
}
/**
进行网络请求
@param key
@param callback
*/
private void loadData(String key, ItemKeyedDataSource.LoadCallback<Teacher.RecordsBean> callback) {
if (!key.equals("0")) {
loadAfter.set(true);
}
/**
当前线程为子线程
这里有坑,一定要使用同步请求,因为方法执行完毕是,监听者就收到监听
*/
Map<String, Object> map = new ArrayMap<>();
map.put("searchContent", "");
map.put("size", config.pageSize);
map.put("current", pageCurrent);
PagingHttpClient.getInstance()
.get("home/paintingList", map, new PagingHttpCallback<Teacher>() {
@Override
protected void onNext(Teacher data) {
//标记分页页数
if (data.getRecords() != null && data.getRecords().size() > 0) {
pageCurrent = data.getCurrent() + 1;
}
callback.onResult(data.getRecords());
if (!key.equals("0")) {
//通过 LiveData 发送数据,告诉 UI 层 是否应该主动关闭上拉加载分页的动画
getBoundaryPageData().postValue(data.getRecords().size() > 0);
loadAfter.set(false);
}
Log.e("TTT", "data===>" + data.toString());
}
@Override
protected void onFail(int code, String message) {
}
});
}
/**
自己处理分页
@param id
@param callback
*/
@SuppressLint("RestrictedApi")
public void loadAfter(String id, ItemKeyedDataSource.LoadCallback<Teacher.RecordsBean> callback) {
if (loadAfter.get()) {
callback.onResult(Collections.emptyList());
return;
}
ArchTaskExecutor.getIOThreadExecutor().execute(new Runnable() {
@Override
public void run() {
loadData(id, callback);
}
});
}
}
adapter 适配器(注意 JavaBean 一定要重写 equals 方法)
package com.paging.study.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.paging.PagedListAdapter;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.paging.study.bean.Teacher;
import cn.yumakeji.jetpackroomstudy.databinding.LayoutTeacherTypeBinding;
import cn.yumakeji.lib_common.global.AppGlobals;
public class HomeAdapter extends PagedListAdapter<Teacher.RecordsBean, HomeAdapter.ViewHolder> {
protected Context mContext;
public HomeAdapter(Context context) {
super(new DiffUtil.ItemCallback<Teacher.RecordsBean>() {
@Override
public boolean areItemsTheSame(@NonNull Teacher.RecordsBean oldItem, @NonNull Teacher.RecordsBean newItem) {
//判断 item 是否相等(这里根据 id 来判断)
return oldItem.getPaintingId() == newItem.getPaintingId();
}
@Override
public boolean areContentsTheSame(@NonNull Teacher.RecordsBean oldItem, @NonNull Teacher.RecordsBean newItem) {
//判断内容是否相等(重写 equals 方法)
return oldItem.equals(newItem);
}
});
this.mContext = context;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutTeacherTypeBinding binding = LayoutTeacherTypeBinding.inflate(LayoutInflater.from(mContext), parent, false);
return new ViewHolder(binding.getRoot(), binding);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.binData(getItem(position));
holder.itemView.setOnClickListener(v -> {
Toast.makeText(AppGlobals.getApplication(), getItem(position).getPaintingName(), Toast.LENGTH_LONG).show();
});
}
public class ViewHolder extends RecyclerView.ViewHolder {
private LayoutTeacherTypeBinding mBinding;
public ViewHolder(@NonNull View itemView, LayoutTeacherTypeBinding binding) {
super(itemView);
this.mBinding = binding;
}
public void binData(Teacher.RecordsBean item) {
mBinding.setItem(item);
}
}
}
适配器布局
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:id="@+id/ll_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="20dp"
android:paddingBottom="20dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="@{item.paintingName}"
android:textSize="24dp"
tools:text="名称" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#eee" />
</LinearLayout>
<data>
<variable
name="item"
type="com.paging.study.bean.Teacher.RecordsBean" />
</data>
</layout>
主页面处理
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.paging.ItemKeyedDataSource;
import androidx.paging.PagedList;
import androidx.paging.PagedListAdapter;
import com.paging.study.AbsListFragment;
import com.paging.study.adapter.HomeAdapter;
import com.paging.study.bean.Teacher;
import com.paging.study.datasource.MutablePageKeyedDataSource;
import com.paging.study.viewmodel.BlankViewModel;
import com.scwang.smartrefresh.layout.api.RefreshLayout;
import java.util.List;
public class BlankFragment extends AbsListFragment<Teacher.RecordsBean, BlankViewModel> {
public static BlankFragment newInstance() {
return new BlankFragment();
}
@Override
protected void onCreateViewFrame(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
}
@Override
public PagedListAdapter getAdapter() {
//return new HomeAdapter(mContext);
return new HomeAdapter(mContext) {
@Override
public void onViewAttachedToWindow(@NonNull ViewHolder holder) {
super.onViewAttachedToWindow(holder);
//进入当前页面,看见了
Log.e("TTT", "onViewAttachedToWindow===>" + holder.getLayoutPosition());
}
@Override
public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
//离开当前页面,看不见了
Log.e("TTT", "onViewDetachedFromWindow===>" + holder.getLayoutPosition());
}
@Override
public void onCurrentListChanged(@Nullable PagedList<Teacher.RecordsBean> previousList, @Nullable PagedList<Teacher.RecordsBean> currentList) {
super.onCurrentListChanged(previousList, currentList);
//这个方法是在我们每提交一次 pagelist 对象到 adapter 就会触发一次
//每调用一次 adpater.submitlist
//防止下拉刷新新加 item 显示不出来
if (previousList != null && currentList != null) {
if (!currentList.containsAll(previousList)) {
mRecyclerView.scrollToPosition(0);
}
}
}
};
}
/**
paging 只要有一次返回味空,就停止分页了,要手动处理
@param refreshLayout
*/
@Override
public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
PagedList<Teacher.RecordsBean> currentList = adapter.getCurrentList();
if (currentList == null || currentList.size() <= 0) {
finishRefresh(false);
return;
}
Teacher.RecordsBean bean = adapter.getCurrentList().get(adapter.getItemCount() - 1);
mViewModel.loadAfter(bean.getPaintingId(), new ItemKeyedDataSource.LoadCallback<Teacher.RecordsBean>() {
@Override
public void onResult(@NonNull List<Teacher.RecordsBean> data) {
PagedList.Config config = currentList.getConfig();
if (data != null && data.size() > 0) {
//这里 咱们手动接管 分页数据加载的时候 使用 MutableItemKeyedDataSource 也是可以的。
//由于当且仅当 paging 不再帮我们分页的时候,我们才会接管。所以 就不需要 ViewModel 中创建的 DataSource 继续工作了,所以使用
//这里主要是将 list 集合转化为 PagedList,给 paging 使用,具体实现抄袭源码
MutablePageKeyedDataSource<Teacher.RecordsBean> dataSource = new MutablePageKeyedDataSource<>();
//这里要把列表上已经显示的先添加到 dataSource.data 中
//而后把本次分页回来的数据再添加到 dataSource.data 中
dataSource.data.addAll(currentList);
dataSource.data.addAll(data);
PagedList<Teacher.RecordsBean> pagedList = dataSource.buildNewPagedList(config);
submitList(pagedList);
}
}
});
}
@Override
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
//invalidate 之后 Paging 会重新创建一个 DataSource 重新调用它的 loadInitial 方法加载初始化数据
//详情见:LivePagedListBuilder#compute 方法
mViewModel.getDataSource().invalidate();
}
}
网络请求封装(注意 paging 的不同)
引入
可单独引入 okhttp
//retrofit:okhttp 封装的网络库
api 'com.squareup.retrofit2:retrofit:2.9.0'
api 'com.squareup.retrofit2:converter-gson:2.9.0'
api 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
api "com.squareup.okhttp3:logging-interceptor:4.7.2"
PagingHttpClient 网络请求核心类
package com.paging.study.http;
import android.util.Log;
import com.yumakeji.rxjava.network.interceptor.CacheIntercepter;
import com.yumakeji.rxjava.network.interceptor.HeaderInterceptor;
import com.yumakeji.rxjava.network.uitils.manager.TrustAllCerts;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.net.FileNameMap;
import java.net.Proxy;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import cn.yumakeji.lib_common.BuildConfig;
import cn.yumakeji.lib_common.global.AppGlobals;
import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
public class PagingHttpClient {
protected OkHttpClient okHttpClient;
protected String sBaseUrl = "https://www.xianghua.art/applets/";
public static PagingHttpClient getInstance() {
return SingletonHolder.sInstance;
}
//静态内部类
private static class SingletonHolder {
private static final PagingHttpClient sInstance = new PagingHttpClient();
}
private PagingHttpClient() {
//缓存地址
File cacheFile = new File(AppGlobals.g
etApplication().getExternalCacheDir(), "Http_Cache");
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50); //大小 50Mb
OkHttpClient.Builder builder = new OkHttpClient
.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.pingInterval(20, TimeUnit.SECONDS)
.proxy(Proxy.NO_PROXY)
//设置缓存方式、时长、地址
.addNetworkInterceptor(new CacheIntercepter())
.addInterceptor(new HeaderInterceptor())
.cache(cache)
.sslSocketFactory(TrustAllCerts.createSSLSocketFactory())
.hostnameVerifier(new TrustAllCerts.TrustAllHostnameVerifier());
if (BuildConfig.DEBUG) { // 判断是否为 debug
// 如果为 debug 模式,则添加日志拦截器
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(@NotNull String message) {
Log.i("hxg_http", message);
}
});
logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
builder.addInterceptor(logging);
}
okHttpClient = builder.build();
}
private HttpEngine.TypeEnum mMediaType = HttpEngine.TypeEnum.FORM;
public void setMediaType(HttpEngine.TypeEnum mediaType) {
this.mMediaType = mediaType;
}
/**
get 请求
@param url
@param params
@return
*/
public void get(String url, Map<String, Object> params, HttpObserver observer) {
String execute = execute(url, params, observer);
if (execute != null) {
observer.onSuccess(execute);
} else {
observer.onError(new RuntimeException("网络连接出错"));
}
}
/**
post 请求
@param url
@param params
@return
*/
public void post(String url, Map<String, Object> params, HttpObserver observer) {
String execute = executePost(url, params);
if (execute != null) {
observer.onSuccess(execute);
} else {
observer.onError(new RuntimeException("网络连接出错"));
}
}
public void postText(String url, String stringJsonOrXml, HttpObserver observer) {
String execute = executePostText(url, stringJsonOrXml, observer);
if (execute != null) {
observer.onSuccess(execute);
} else {
observer.onError(new RuntimeException("网络连接出错"));
}
}
private String executePost(String url, Map<String, Object> params) {
try {
Response execute = postCall(sBaseUrl + url, params).execute();
ResponseBody body = execute.body();
return body.string();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private String executePostText(String url, String stringJsonOrXml, HttpObserver observer) {
try {
Response execute = postCall(sBaseUrl + url, stringJsonOrXml).execute();
ResponseBody body = execute.body();
return body.string();
} catch (IOException e) {
e.printStackTrace();
observer.onError(e);
}
return null;
}
/**
Post 请求
@param url
@param params
@return
*/
private Call postCall(String url, Map<String, Object> params) {
RequestBody requestBody = appendBody(params, mMediaType);
Request.Builder builder = new Request.Builder();
Request request = builder.post(requestBody).url(url).build();
Call call = okHttpClient.newCall(request);
return call;
}
private Call postCall(String url, String stringJsonOrXml) {
MediaType mediaType = MediaType.parse(getTypeEnum(mMediaType));//"类型,字节码"
RequestBody requestBody = RequestBody.create(mediaType, stringJsonOrXml);
Request.Builder builder = new Request.Builder();
Request request = builder.post(requestBody).url(url).build();
Call call = okHttpClient.newCall(request);
return call;
}
/**
组装 post 请求参数 body
@param params
@return
*/
private RequestBody appendBody(Map<String, Object> params, HttpEngine.TypeEnum mediaType) {
MultipartBody.Builder builder = new MultipartBody.Builder()
.setType(getMediaType(mediaType));
addParams(builder, params);
return builder.build();
}
/**
添加参数
判断是否能上传文件
*/
private void addParams(MultipartBody.Builder builder, Map<String, Object> params) {
if (params != null && !params.isEmpty()) {
for (String key : params.keySet()) {
Object value = params.get(key);
if (value instanceof File) {
File file = (File) value;
builder.addFormDataPart(key, file.getName(),
RequestBody.create(MediaType
.parse(guessMineType(file.getAbsolutePath())),
file));
} else if (value instanceof List) {
//代表提交的是 List 集合
try {
List<File> fileList = (List<File>) value;
for (int i = 0; i < fileList.size(); i++) {
//获取文件
File file = fileList.get(i);
builder.addFormDataPart(key + i, file.getName(),
RequestBody.create(MediaType
.parse(guessMineType(file.getAbsolutePath())),
file));
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
builder.addFormDataPart(key, String.valueOf(value));
}
}
}
}
private String guessMineType(String path) {
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String contentTypeFor = fileNameMap.getContentTypeFor(path);
if (contentTypeFor == null) {
contentTypeFor = "application/octet-stream";
}
return contentTypeFor;
}
private String getTypeEnum(HttpEngine.TypeEnum typeEnum) {
switch (typeEnum) {
case XML:
return "application/xml; charset=utf-8";
case JSON:
return "application/json; charset=utf-8";
case URLENCODED:
return "application/x-www-form-urlencoded;charset=utf-8";
}
return "application/json; charset=utf-8";
}
private MediaType getMediaType(HttpEngine.TypeEnum typeEnum) {
switch (typeEnum) {
case MIXED:
return MultipartBody.MIXED;
case ALTERNATIVE:
return MultipartBody.ALTERNATIVE;
case DIGEST:
return MultipartBody.DIGEST;
case PARALLEL:
return MultipartBody.PARALLEL;
case FORM:
return MultipartBody.FORM;
}
return MultipartBody.FORM;
}
/**
get 请求
@param url
@param params
@return
*/
private Call getCall(String url, Map<String, Object> params) {
String jointUrl = URLUtil.jointParams(sBaseUrl + url, params);
Request.Builder builder = new Request.Builder();
Request request = builder.get().url(jointUrl).build();
Call call = okHttpClient.newCall(request);
return call;
}
private String execute(String url, Map<String, Object> params, HttpObserver observer) {
try {
Response execute = getCall(url, params).execute();
ResponseBody body = execute.body();
return body.string();
} catch (IOException e) {
e.printStackTrace();
observer.onError(e);
}
return null;
}
}
HttpEngine
public class HttpEngine {
enum TypeEnum {
XML,
JSON,
URLENCODED,
MIXED,
ALTERNATIVE,
DIGEST,
PARALLEL,
FORM
}
}
URLUtil
public class URLUtil {
/**
拼接参数
*/
public static String jointParams(String url,Map<String,Object> params){
if (params==null||params.size()<=0){
return url;
}
StringBuffer stringBuffer=new StringBuffer(url);
if (!url.contains("?")){
stringBuffer.append("?");
}else {
if (!url.endsWith("?")){
stringBuffer.append("&");
}
}
for (Map.Entry<String, Object> entry : params.entrySet()) {
stringBuffer.append(entry.getKey()+"="+entry.getValue()+"&");
}
stringBuffer.deleteCharAt(stringBuffer.length()-1);
return stringBuffer.toString();
}
/**
解析一个类上面的 class 信息
*/
public static Class<?> analysisClazzInfo(Object object){
Type getType = object.getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType) getType).getActualTypeArguments();
return (Class<?>) params[0];
}
}
回调
public interface HttpObserver {
void onError(@NonNull Throwable e);
void onSuccess(String s);
}
import com.alibaba.fastjson.JSON;
import com.yumakeji.rxjava.network.bean.Result;
import com.yumakeji.rxjava.network.error.HttpThrowable;
import com.yumakeji.rxjava.network.error.ThrowableHandler;
import com.yumakeji.rxjava.network.unify.UnifyCallback;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.reflect.ParameterizedType;
import io.reactivex.rxjava3.annotations.NonNull;
public abstract class PagingHttpCallback<T> implements HttpObserver {
@Override
public void onSuccess(String result) {
try {
JSONObject jsonObject = new JSONObject(result);
Result result1 = new Result();
result1.setCode(jsonObject.getInt("code"));
result1.setMessage(jsonObject.getString("message"));
result1.data = jsonObject.getString("data");
if (!result1.isOk()) {
UnifyCallback.handleUnifyCode(result1.getCode(), result1.getMessage());
onFail(result1.getCode(), result1.getMessage());
return;
}
//解析,获取类上面的泛型
Class<T> dataClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
T data = JSON.parseObject(result1.data.toString(), dataClass);
onNext(data);
} catch (JSONException e) {
e.printStackTrace();
}
}
protected abstract void onNext(T data);
protected abstract void onFail(int code, String message);
@Override
public void onError(@NonNull Throwable throwable) {
if (throwable instanceof Exception) {
onFail(ThrowableHandler.handleThrowable(throwable));
} else {
onFail(new HttpThrowable(HttpThrowable.UNKNOWN, "未知错误", throwable));
}
}
//应用中具体实现的是下面这个 onFail 方法
private void onFail(HttpThrowable httpThrowable) {
onFail(httpThrowable.errorType, httpThrowable.message);
}
}
其他
MutableItemKeyedDataSource
package com.paging.study.datasource;
import android.annotation.SuppressLint;
import androidx.annotation.NonNull;
import androidx.arch.core.executor.ArchTaskExecutor;
import androidx.paging.ItemKeyedDataSource;
import androidx.paging.PagedList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
一个可变更的 ItemKeyedDataSource 数据源
<p>
工作原理是:我们知道 DataSource 是会被 PagedList 持有的。
一旦,我们调用了 new PagedList.Builder<Key, Value>().build(); 那么就会立刻触发当前 DataSource 的 loadInitial()方法,而且是同步
详情见 ContiguousPagedList 的构造函数,而我们在当前 DataSource 的 loadInitial()方法中返回了 最新的数据集合 data。
一旦,我们再次调用 PagedListAdapter#submitList()方法 就会触发差分异计算 把新数据变更到列表之上了。
@param <Key>
@param <Value>
*/
@SuppressLint("RestrictedApi")
public abstract class MutableItemKeyedDataSource<Key, Value> extends ItemKeyedDataSource<Key, Value> {
private ItemKeyedDataSource mDataSource;
public List<Value> data = new ArrayList<>();
public PagedList<Value> buildNewPagedList(PagedList.Config config) {
PagedList<Value> pagedList = new PagedList.Builder<Key, Value>(this, config)
.setFetchExecutor(ArchTaskExecutor.getIOThreadExecutor())
.setNotifyExecutor(ArchTaskExecutor.getMainThreadExecutor())
.build();
return pagedList;
}
public MutableItemKeyedDataSource(ItemKeyedDataSource dataSource) {
mDataSource = dataSource;
}
@Override
public void loadInitial(@NonNull LoadInitialParams<Key> params, @NonNull LoadInitialCallback<Value> callback) {
callback.onResult(data);
}
@Override
public void loadAfter(@NonNull LoadParams<Key> params, @NonNull LoadCallback<Value> callback) {
if (mDataSource != null) {
//一旦 和当前 DataSource 关联的 PagedList 被提交到 PagedListAdapter。那么 ViewModel 中创建的 DataSource 就不会再被调用了
//我们需要在分页的时候 代理一下 原来的 DataSource,迫使其继续工作
mDataSource.loadAfter(params, callback);
}
}
@Override
public void loadBefore(@NonNull LoadParams<Key> params, @NonNull LoadCallback<Value> callback) {
callback.onResult(Collections.emptyList());
}
@NonNull
@Override
public abstract Key getKey(@NonNull Value item);
}
MutablePageKeyedDataSource
package com.paging.study.datasource;
import android.annotation.SuppressLint;
import androidx.annotation.NonNull;
import androidx.arch.core.executor.ArchTaskExecutor;
import androidx.paging.PageKeyedDataSource;
import androidx.paging.PagedList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
具体原理见 {@link MutableItemKeyedDataSource}
@param <Value>
*/
@SuppressLint("RestrictedApi")
public class MutablePageKeyedDataSource<Value> extends PageKeyedDataSource<Integer, Value> {
public List<Value> data = new ArrayList<>();
public PagedList<Value> buildNewPagedList(PagedList.Config config) {
PagedList<Value> pagedList = new PagedList.Builder<Integer, Value>(this, config)
.setFetchExecutor(ArchTaskExecutor.getIOThreadExecutor())
.setNotifyExecutor(ArchTaskExecutor.getMainThreadExecutor())
.build();
return pagedList;
}
@Override
public void loadInitial(@NonNull LoadInitialParams<Integer> params, @NonNull LoadInitialCallback<Integer, Value> callback) {
callback.onResult(data, null, null);
}
@Override
public void loadBefore(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, Value> callback) {
callback.onResult(Collections.emptyList(), null);
}
@Override
public void loadAfter(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, Value> callback) {
callback.onResult(Collections.emptyList(), null);
}
}
javabean
public class Teacher extends BaseResult {
private int current;
private int pages;
private int size;
private int total;
private List<RecordsBean> records;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Teacher)) return false;
Teacher teacher = (Teacher) o;
return getCurrent() == teacher.getCurrent() &&
getPages() == teacher.getPages() &&
getSize() == teacher.getSize() &&
getTotal() == teacher.getTotal() &&
Objects.equals(getRecords(), teacher.getRecords());
}
@Override
public int hashCode() {
return Objects.hash(getCurrent(), getPages(), getSize(), getTotal(), getRecords());
}
public int getCurrent() {
return current;
}
public void setCurrent(int current) {
this.current = current;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public List<RecordsBean> getRecords() {
return records;
}
public void setRecords(List<RecordsBean> records) {
this.records = records;
}
public static class RecordsBean {
private String createTime;
private int difficultyIndex;
private String direction;
private String headImgUrl;
private int isVip;
private String label;
private String paintingId;
private String paintingName;
private String readCount;
private String showNew;
private String studyAge;
private String titlePage;
private int type;
private String userName;
private String videoId;
private String videoName;
private List<LabelListBean> labelList;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof RecordsBean)) return false;
RecordsBean that = (RecordsBean) o;
return getDifficultyIndex() == that.getDifficultyIndex() &&
getIsVip() == that.getIsVip() &&
getType() == that.getType() &&
Objects.equals(getCreateTime(), that.getCreateTime()) &&
Objects.equals(getDirection(), that.getDirection()) &&
Objects.equals(getHeadImgUrl(), that.getHeadImgUrl()) &&
Objects.equals(getLabel(), that.getLabel()) &&
Objects.equals(getPaintingId(), that.getPaintingId()) &&
Objects.equals(getPaintingName(), that.getPaintingName()) &&
Objects.equals(getReadCount(), that.getReadCount()) &&
Objects.equals(getShowNew(), that.getShowNew()) &&
Objects.equals(getStudyAge(), that.getStudyAge()) &&
Objects.equals(getTitlePage(), that.getTitlePage()) &&
Objects.equals(getUserName(), that.getUserName()) &&
Objects.equals(getVideoId(), that.getVideoId()) &&
Objects.equals(getVideoName(), that.getVideoName()) &&
Objects.equals(getLabelList(), that.getLabelList());
}
@Override
public int hashCode() {
return Objects.hash(getCreateTime(), getDifficultyIndex(), getDirection(), getHeadImgUrl(), getIsVip(), getLabel(), getPaintingId(), getPaintingName(), getReadCount(), getShowNew(), getStudyAge(), getTitlePage(), getType(), getUserName(), getVideoId(), getVideoName(), getLabelList());
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
public int getDifficultyIndex() {
return difficultyIndex;
}
public void setDifficultyIndex(int difficultyIndex) {
this.difficultyIndex = difficultyIndex;
}
public String getDirection() {
return direction;
}
public void setDirection(String direction) {
this.direction = direction;
}
public String getHeadImgUrl() {
return headImgUrl;
}
public void setHeadImgUrl(String headImgUrl) {
this.headImgUrl = headImgUrl;
}
public int getIsVip() {
return isVip;
}
public void setIsVip(int isVip) {
this.isVip = isVip;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getPaintingId() {
return paintingId;
}
public void setPaintingId(String paintingId) {
this.paintingId = paintingId;
}
public String getPaintingName() {
return paintingName;
}
public void setPaintingName(String paintingName) {
this.paintingName = paintingName;
}
评论