本页面由葡萄牙语机器翻译,可能存在错误。葡萄牙语版本为准。
8. 加载数据
你将学到: 在不卡住 UI 的情况下获取数据,并高效展示大型列表。前置条件: 管理状态。
完整示例(复制、粘贴、运行)
在后台 Thread 中加载数据,用 Component.onUI 回到绘制线程,并在一个会回收视图的虚拟化列表(VirtualListView + DataAdapter)中展示。可直接编译运行。
package com.exemplo;
import java.util.*;
import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
public class MainWindow extends Window
{
private final List<Tarefa> tarefas = new ArrayList<>();
private VirtualListView lista;
@Override
public void onShow() throws Exception
{
super.onShow();
setLayout(new VerticalLayout());
lista = new VirtualListView(Relative.ofFont(3f), new DataAdapter()
{
public int getCount() { return tarefas.size(); }
public Component createView() { return new Label(""); } // 创建一次
public void bindView(Component v, int i) { ((Label) v).setText(tarefas.get(i).titulo); }
});
add(LAY_FILL, lista);
carregar();
}
private void carregar()
{
new Thread(() -> {
var dados = listarDoRepositorio(); // 繁重工作,后台 thread
Component.onUI(() -> { // 返回 paint thread
tarefas.clear();
tarefas.addAll(dados);
lista.notifyDataChanged(); // 更新虚拟化列表
});
}).start();
}
private List<Tarefa> listarDoRepositorio() // 模拟 I/O
{
List<Tarefa> out = new ArrayList<>();
for (int i = 1; i <= 500; i++) out.add(new Tarefa("Tarefa " + i));
return out;
}
}
class Tarefa
{
final String titulo;
Tarefa(String titulo) { this.titulo = titulo; }
}
下面的片段只展示核心部分(放在
onShow()里的内容)。要运行,请把它们放进上面的MainWindow骨架里。
为什么 I/O 从不在绘制线程上进行
UI 只在一个线程上运行 —— 其中任何阻塞都会冻结界面。必须遵循的模式:
new Thread(() -> {
var dados = repo.listar(); // 繁重工作,后台 thread
Component.onUI(() -> { // 返回 paint thread
vm.tarefas = dados;
lista.notifyDataChanged(); // 更新虚拟化列表
});
}).start();
若要对一个已在后台的 UI 事件做出反应,请使用 onActionThread(见处理输入)。
大型列表:VirtualListView + DataAdapter
VirtualListView 回收视图 —— 只渲染可见部分。adapter 将创建(一次)与绑定(廉价,多次)分离开来:
VirtualListView lista = new VirtualListView(Relative.ofFont(3f), new DataAdapter() {
public int getCount() { return vm.tarefas.size(); }
public Component createView() throws Exception { return new CardTarefa(); }
public void bindView(Component v, int i) throws Exception { ((CardTarefa) v).bind(vm.tarefas.get(i)); }
});
add(LAY_FILL, lista);
// 当数据变化时:
lista.notifyDataChanged();
bindView在滚动时会运行非常多次 —— 保持它廉价且幂等(切勿在其中做 I/O)。
本步骤所构建的
列表转为在后台加载并进行虚拟化渲染(使用第 3 章的 CardTarefa)。
回顾
I/O 在 Thread 中 → Component.onUI;大型列表用 VirtualListView(通过 createView/bindView 回收);数据变化时调用 notifyDataChanged()。
下一步
→ 持久化数据
另见
这个页面有帮助吗?感谢你的反馈!