android - 用于搜索查询的 Android 分页
问题描述
我是 android 开发的新手,正在尝试为我的应用程序构建 UI。该应用程序与 REST 后端集成,后者接受搜索查询和项目列表作为响应。
interface RetrofitEndpoint {
@GET("paged/list/endpoint")
Call<PagedList<Object>> getPagedList(@Query("query") String query, @Query("pageSize") int pageSize, Query("pageOffset") int pageOffset);
}
UI 一次向用户显示一个项目。
我正在将列表加载到 recyclerview
public class SomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Object> list;
// .. other overridden members
public void setList(List<Object> list) {
this.list = list;
notifyDataSetChanged();
}
public void addAll(List<Object> newList) {
int lastIndex = list.size() - 1;
list.addAll(newList);
notifyItemRangeInserted(lastIndex, newList.size());
}
}
我无法弄清楚的部分是当我到达回收站视图的末尾(或之前以避免延迟)时如何加载更多数据,是否有任何库/API可以做到这一点?
解决方案
要使分页列表正常工作,它需要在您的应用程序中添加更多内容。此实现使用视图模型、实时数据和房间持久性,因此它可以离线工作。
你的 build.gradle:
// ViewModel
def lifecycle_version = "2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
def room_version = "2.2.5"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
def paging_version = "2.1.2"
implementation "androidx.paging:paging-runtime:$paging_version"
改造api:
interface RetrofitEndpoint {
@GET("paged/list/endpoint")
Call<List<YourObject>> getYourObjectList(@Query("query") String query, @Query("pageSize") int pageSize, Query("pageOffset") int pageOffset);
}
你的对象:
@Entity(tableName = "your_object")
public class YourObject implements Serializable {
@PrimaryKey(autoGenerate = true)
private int db_id;
...
道:
@Dao
public interface YourObjectDao{
/**
* Get your objects from the table.
* -------------------------------
* We get update every time the database update.
*
*
* @return your object from the table
*/
@Insert
void insert(YourObject yourObject);
@Insert
void insertList(List<YourObject> yourObjectList);
@Query("SELECT * FROM your_object")
DataSource.Factory<Integer, YourObject> getAllResults();
@Query("DELETE FROM your_object")
void deleteAll();
}
数据库:
@androidx.room.Database(entities = {YourObject.class}, version = 1)
public abstract class Database extends RoomDatabase {
private static Database instance;
public abstract YourObjectDao get_your_object_dao();
public static synchronized Database getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(context.getApplicationContext(),
Database.class, DATABASE_NAME)
.fallbackToDestructiveMigration()
.addCallback(roomCallback)
.build();
}
return instance;
}
}
YourObjectBoundaryCallback:
public class YourObjectBoundaryCallback extends PagedList.BoundaryCallback<YourObject> {
private AppExecutors executors;
private Database database;
private YourObjectDao dao;
private Integer page_number;
public YourObjectBoundaryCallback (Application application, AppExecutors executors) {
//super();
this.executors = executors;
database = Database.getInstance(application);
dao = database.get_your_object_dao();
page_number=1;
}
@Override
public void onZeroItemsLoaded() {
super.onZeroItemsLoaded();
Log.d("log", "yourObjects onzeroitemsloaded");
fetchYourObjects(page_number);
}
@Override
public void onItemAtFrontLoaded(@NonNull YourObject itemAtFront) {
super.onItemAtFrontLoaded(itemAtFront);
Log.d("log", "yourObjects onItemAtFrontLoaded");
}
@Override
public void onItemAtEndLoaded(@NonNull YourObject itemAtEnd) {
super.onItemAtEndLoaded(itemAtEnd);
Log.d("log", "yourObjects onItemAtEndLoaded");
page_number=page_number+1;
fetchYourObjects(page_number);
}
public void fetchYourObjects(int pageNumber) {
RetrofitApi retrofitApi = RetrofitInstance.getRetrofitEndpoint();
Call<List<YourObject>> call = retrofitApi.getYourObjectList(query, pageSize,pageNumber);
call.enqueue(new Callback<List<YourObject>>() {
@Override
public void onResponse(Call<List<YourObject>> call, Response<List<YourObject>> response) {
if (!response.isSuccessful()) {
Log.d("log", "YourObjects Response unsuccesful: " + response.code());
return;
}
Log.d("log", "YourObjects Response ok: " + response.code());
List<YourObject> yourObjectsList = response.body();
insertListToDb(yourObjectsList );
}
@Override
public void onFailure(Call<List<YourObject>> call, Throwable t) {
Log.d("log", "yourObjects onFailure: " + t.getMessage());
}
});
}
public void insertListToDb(List<YourObject> list) {
Runnable runnable = () -> {
dao.insertList(list);
};
Runnable diskRunnable = () -> database.runInTransaction(runnable);
executors.diskIO().execute(diskRunnable);
}
}
YourObjects 存储库:
public class YourObjectsRepository {
private LiveData<PagedList<YourObject>> yourObjectsPagedList;
private YourObjectBoundaryCallback yourObjectsBoundaryCallback;
private AppExecutors executors;
public YourObjectsRepository (Application application, AppExecutors executors) {
this.executors = executors;
Database database = Database.getInstance(application);
YourObjectDao dao = database.get_your_object_dao();
yourObjectsBoundaryCallback= new YourObjectBoundaryCallback (application, executors);
createYourObjectsPagedList(dao );
}
//this is configuration for your paged list, adjust per your requirements
private PagedList.Config getPagedListConfig(){
return (new PagedList.Config.Builder())
.setEnablePlaceholders(false)
.setPrefetchDistance(40)
.setInitialLoadSizeHint(60)
.setPageSize(20).build();
}
private void createYourObjectsPagedList(YourObjectDao dao){
yourObjectsPagedList= new LivePagedListBuilder<>(dao.getAllResults(), getPagedListConfig())
.setBoundaryCallback(yourObjectsBoundaryCallback).setFetchExecutor(executors.networkIO())
.build();
}
public LiveData<PagedList<YourObject>> getYourObjectsPagedList() {
return yourObjectsPagedList;
}
}
你的对象视图模型:
public class YourObjectsViewModel extends AndroidViewModel {
private YourObjectsRepository repo;
public YourObjectsViewModel (@NonNull Application application) {
super(application);
AppExecutors executors = new AppExecutors();
repo= new YourObjectsRepository (application, executors);
}
public LiveData<PagedList<YourObject>> getYourObjectsPagedList() {
return repo.getYourObjectsPagedList();
}
}
应用程序执行者:
public class AppExecutors {
private final Executor diskIO;
private final Executor networkIO;
private final Executor mainThread;
private final Executor others;
private final Executor paging;
public AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread, Executor others, Executor paging) {
this.diskIO = diskIO;
this.networkIO = networkIO;
this.mainThread = mainThread;
this.others = others;
this.paging = paging;
}
public AppExecutors() {
this(Executors.newSingleThreadExecutor(), Executors.newFixedThreadPool(3),
new MainThreadExecutor(), Executors.newSingleThreadExecutor(),
Executors.newFixedThreadPool(4));
}
public Executor diskIO() {
return diskIO;
}
public Executor networkIO() {
return networkIO;
}
public Executor mainThread() {
return mainThread;
}
public Executor others() {
return others;
}
public Executor paging() {
return paging;
}
private static class MainThreadExecutor implements Executor {
private Handler mainThreadHandler = new Handler(Looper.getMainLooper());
@Override
public void execute(@NonNull Runnable command) {
mainThreadHandler.post(command);
}
}
}
在您的活动/片段中:
yourObjectsViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication())).get(YourObjectsViewModel.class);
yourObjectsViewModel.getYourObjectPagedList().observe(getViewLifecycleOwner(), new Observer<PagedList<TopRatedMovie>>() {
@Override
public void onChanged(PagedList<YourObject> results) {
Log.d("log", " onChanged list size: " + results.size());
yourAdapter.submitList(results);
}
});
在您的适配器中:
public class YourPagedListAdapter extends PagedListAdapter<YourObject,
RecyclerView.ViewHolder> {
如果您有任何问题,请随时提问。
推荐阅读
- embedded-linux - imx6ul - 如何为 sdcard 图像选择正确的 dts?
- python - 如何为多个用户提供持续运行的 python 脚本(社交媒体机器人)
- clion - 如何触发对具有与检查功能相同签名的自定义功能的现有检查?
- javascript - 保存所选选项不适用于 jquery
- c# - C# 桌面应用程序 - 如何保存默认管理员用户名和密码
- python - 如何numpy-ify二维条件查找?
- arrays - 将数组拆分为子数组,以便我们拥有最少数量的子数组且元素总和 < k
- text-processing - 有没有办法通过合并重复项和制表符非重复项来将多行解析为单行?
- javascript - Javascript:检查匹配属性,箭头函数不会在 for 循环中更新 i
- backbone.js - 如何从 localStorage 集合中删除 Backbone 模型