本页面由葡萄牙语机器翻译,可能存在错误。葡萄牙语版本为准。
如何在虚拟列表中对服务器数据进行分页
目的。 显示一个源为分页(例如:REST API)的大型数据集,而无需一次性加载全部内容。
PagedDataAdapter 维护一个页面的 LRU 缓存:内存中只保留有限数量的页面;当滚动到
数据已被丢弃的区域时,会显示加载指示器并通过 loadPage 重新加载该页面。
在页面加载期间滚动会被锁定。
使用的 API
abstract class PagedDataAdapter(int pageSize, int maxCachedPages)— 每页pageSize项;内存中最多maxCachedPages页(LRU)。实现VirtualListView.DataAdapter。abstract int getTotalCount()— 服务器上的项目总数(成为列表的getCount())。abstract void loadPage(int pageIndex, PageCallback callback)— 异步加载一个页面;完成后调用callback.onPageLoaded(pageIndex, items)。可从任何线程调用——列表会切换到 UI 线程。abstract Component createView() throws Exception— 创建可重用的空白视图。abstract void bindItem(Component view, Object item, int index) throws Exception— 用项目的对象填充视图(而非文本)。与原始的bindView不同:这里你接收的是页面已解析好的项。interface PageCallback { void onPageLoaded(int pageIndex, Object[] items); }PagedDataAdapter.isAvailable(int index)— 如果索引已在缓存中则为 true。PagedDataAdapter.clearCache()— 清除缓存和加载状态。
完整示例(复制、粘贴并运行)
package com.exemplo;
import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.graphics.*; // Relative(用于 VirtualListView)
/** 可执行的主界面。将 launcher 指向此类(classname)并运行:gradlew :lwjgl3:run */
public class MainWindow extends Window
{
/** 模拟的业务项 — 替换为你真实的实体。 */
static class Registro
{
final String nome;
Registro(String nome) { this.nome = nome; }
String getNome() { return nome; }
}
static final int totalNoServidor = 12345; // 例如:API 的 metadata
@Override
public void onShow() throws Exception
{
super.onShow();
setLayout(new VerticalLayout());
PagedDataAdapter adapter = new PagedDataAdapter(20, 5) // 每页 20 项,内存中缓存 5 页
{
public int getTotalCount()
{
return totalNoServidor;
}
public void loadPage(int pageIndex, PageCallback callback)
{
// 异步:这里在后台模拟服务器响应
onUI(() ->
{
Object[] registros = new Object[20];
for (int i = 0; i < registros.length; i++)
registros[i] = new Registro("Item " + (pageIndex * 20 + i));
callback.onPageLoaded(pageIndex, registros);
});
}
public Component createView() throws Exception
{
return new Label(""); // 可复用的简单行
}
public void bindItem(Component view, Object item, int index) throws Exception
{
Registro r = (Registro) item; // 该页中已解析好的项
((Label) view).setText(r.getNome());
}
};
// PagedDataAdapter 是一个 DataAdapter:直接传给 VirtualListView
VirtualListView lista = new VirtualListView(Relative.ofFont(3f), adapter);
add(LAY_FILL, lista);
}
}
下面的片段只展示核心部分。要运行它,请将其放入上面的
MainWindow骨架中。
最小片段
// 已在源码核实:PagedDataAdapter.java
PagedDataAdapter adapter = new PagedDataAdapter(20, 5) // 每页 20 项,内存中缓存 5 页
{
public int getTotalCount()
{
return totalNoServidor; // 例如:12345(来自 API 的 metadata)
}
public void loadPage(int pageIndex, PageCallback callback)
{
// 异步:发起请求并通过回调响应
api.buscarPagina(pageIndex, 20, registros ->
callback.onPageLoaded(pageIndex, registros)); // registros = Object[]
}
public Component createView() throws Exception
{
return new Label(""); // 可复用的简单行
}
public void bindItem(Component view, Object item, int index) throws Exception
{
Registro r = (Registro) item; // 该页中已解析好的项
((Label) view).setText(r.getNome());
}
};
// PagedDataAdapter 是一个 DataAdapter:直接传给 VirtualListView
VirtualListView lista = new VirtualListView(Relative.ofFont(3f), adapter);
layout.add(1f, lista);
深入了解
VirtualListView在构造函数中自动与 adapter 绑定(adapter.listView = this)——无需手动关联。- 当
loadPage正在进行时,adapter 会标记waitingForData,VirtualListView会阻止 pan/fling/wheel 并暂停当前的 fling(页面到达时恢复)。 - 通过追加实现无限滚动(无 LRU 缓存),参见 carregar-mais.md。
- 组件指南:PagedDataAdapter · 最佳实践:性能与大型列表 · 权威来源:第 15 章
这个页面有帮助吗?感谢你的反馈!