本页面由葡萄牙语机器翻译,可能存在错误。葡萄牙语版本为准。
如何在 paint 线程之外访问数据库
目的。 繁重的查询(扫描、批量操作、迁移)如果在 CrossFly 唯一的 paint 线程上运行,会导致 UI 卡死。规则是:在工作线程中执行数据库 I/O,并且仅通过 Component.onUI(...) 更新 UI,它会将代码重新转发到 UI 线程。
使用的 API
new Thread(Runnable).start()—— 创建一个工作线程用于访问数据库。所有SqliteDb/query/bulkInsert都在这里运行,远离 paint 线程。Component.onUI(Runnable r)—— 将r排入队列,使其在 UI 线程上运行(内部为Gdx.app.postRunnable)。所有对组件的操作(设置文本、向列表添加项、repaint)都必须在此回调内发生。SqliteDb/SqliteCursor—— 在其自身线程内打开并关闭(通过try-with-resources)。不要在线程之间共享连接;在你使用的地方打开你自己的连接。
线程处理黄金法则。 读/写数据库:工作线程。触碰 UI 组件:
Component.onUI。绝不能反过来——在 UI 线程之外访问组件会造成损坏;用 I/O 阻塞 paint 线程会使应用卡死。
离开线程前先收集。
SqliteCursor是AutoCloseable且与其连接绑定。不要把 cursor 传入onUI。在工作线程中将数据物化(例如放入一个List),并只把准备好的列表传给 UI。
完整示例(复制、粘贴并运行)
package com.exemplo;
import java.util.*; // List, ArrayList
import dev.crossfly.ui.*; // Window, Component
import dev.crossfly.ui.layout.*; // VerticalLayout
import dev.crossfly.sqlite.*; // SqliteDb, SqliteCursor
/** 可执行的主界面。将 launcher 指向此类(classname)并运行:gradlew :lwjgl3:run */
public class MainWindow extends Window
{
@Override
public void onShow() throws Exception
{
super.onShow();
setLayout(new VerticalLayout());
new Thread(() ->
{
// --- 工作 thread:数据库 I/O ---
List<String> nomes = new ArrayList<>();
try (SqliteDb db = SqliteDb.open("app.db");
SqliteCursor c = db.query("SELECT name FROM person ORDER BY name"))
{
while (c.next())
nomes.add(c.getString(0)); // 在离开 thread 之前采集
}
// --- 仅为更新组件而回到 UI ---
Component.onUI(() ->
{
// 此处可安全操作组件(设置列表、repaint 等)
preencheLista(nomes);
});
}).start();
}
/** Stub:在此用加载的数据更新你的 UI 组件。 */
private void preencheLista(List<String> nomes)
{
// 例如:在列表中构建项、设置文本、repaint()...
}
}
下面的代码片段仅展示核心部分。要运行它,请将其放入上面的
MainWindow骨架中。
最小片段
// 已在源码核实:Component.onUI (Gdx.app.postRunnable),SqliteDb.query/cursor 从 0 开始
import dev.crossfly.sqlite.*;
import dev.crossfly.ui.Component;
import java.util.*;
new Thread(() ->
{
// --- 工作 thread:数据库 I/O ---
List<String> nomes = new ArrayList<>();
try (SqliteDb db = SqliteDb.open("app.db");
SqliteCursor c = db.query("SELECT name FROM person ORDER BY name"))
{
while (c.next())
nomes.add(c.getString(0)); // 在离开 thread 之前采集
}
// --- 仅为更新组件而回到 UI ---
Component.onUI(() ->
{
// 此处可安全操作组件(设置列表、repaint 等)
preencheLista(nomes);
});
}).start();
深入了解
这个页面有帮助吗?感谢你的反馈!