Java ObservableList首次加载正常后续刷新耗时陡增问题排查
问题根因
- 单元素添加触发高频变更事件:ObservableList的
add()方法每执行一次就会触发一次变更事件,你绑定了该列表的ChoiceBox、自动补全组件每次都会响应事件执行重绘、索引更新等操作,N条数据就会触发N次事件,开销随数据量线性增长。 - 监听器堆叠泄漏:你每次执行刷新方法都会重复调用
TextFields.bindAutoCompletion()、choiceBoxAuthor.setItems(),旧的绑定监听器没有被解绑,相当于每次刷新都在列表上叠加一层新的监听器,刷新次数越多,单次add()需要触发的监听器数量越多,这是你耗时随刷新次数上涨的核心原因。 - 代码笔误冗余:从现有代码看,你清空的是
bookAttributes.listAuthors,循环写入的是bookAttributes.authors,绑定自动补全用的又是listAuthors,两个列表逻辑混淆,也会增加不必要的开销。
修复方案
1. 移除重复绑定逻辑
绑定操作只需要在控制器初始化时执行一次,不需要每次刷新都重复绑定,ObservableList内容更新后UI会自动同步:
// 控制器初始化方法中仅执行一次 @Override public void initialize(URL url, ResourceBundle resourceBundle) { choiceBoxAuthor.setItems(bookAttributes.authors); TextFields.bindAutoCompletion(textFieldAuthor, bookAttributes.authors); }
2. 批量更新ObservableList
不要在循环内逐个调用add(),先把拼接好的作者名存入普通ArrayList,最后一次性替换ObservableList的全部内容,仅触发一次变更事件:
public void createAuthorHashMap() throws Exception { String authorFirstName, authorMiddleName, authorLastName, authorFullName; int ID; // 从数据库拉取所有作者的CachedRowSet结果集 CachedRowSet authorList = connectionCommands.readDatabase(sqlCommands.selectAllAuthor); // 清空哈希映射 bookAttributes.bidiMapAuthors.clear(); // 先把结果存入普通ArrayList List<String> tempAuthors = new ArrayList<>(); while (authorList.next()) { ID = authorList.getInt(1); authorFirstName = authorList.getString(2); authorMiddleName = authorList.getString(3); authorLastName = authorList.getString(4); if (authorMiddleName == null) { authorFullName = (authorFirstName + " " + authorLastName); } else { authorFullName = (authorFirstName + " " + authorMiddleName + " " + authorLastName); } bookAttributes.bidiMapAuthors.put(ID, authorFullName); tempAuthors.add(authorFullName); } // 一次性更新ObservableList,仅触发一次变更事件 bookAttributes.authors.setAll(tempAuthors); }
3. 线程安全检查
如果你的刷新方法是在后台线程执行,所有对ObservableList的操作必须包裹在Platform.runLater()中,放到JavaFX主线程执行,避免出现UI异常和额外性能开销。
内容的提问来源于stack exchange,提问作者TeaDrinker
相关产品推荐
相关产品推荐

