JavaFX8 -- TableView中TableCell物件管理的奇怪問題-多次非同步重新整理單元格慎重!
阿新 • • 發佈:2019-01-23
早前,我在JavaFX2(JDK 7)中自定義了一個TextFieldTableCell,對TextField實現了一些特定的事件監聽以及觸發TableView再次重新整理等,以下是簡單的程式碼
import javafx.application.Platform; import javafx.scene.control.TableCell; import javafx.scene.control.TextField; public class TextfieldTableCell extends TableCell<MyTableData, String> { public TextfieldTableCell() { } @Override protected void updateItem(String item, boolean empty) { super.updateItem(item, empty); updateGraphic(); } private void updateGraphic() { setText(null); setGraphic(null); final int index = getIndex(); if (isEmpty() || index < 0) { } else { final TextField textField = new TextField(); textField.textProperty().addListener(new ChangeListener<String>() { @Override public void changed(ObservableValue<? extends String> ov, String t, String t1){ //ignore some action handler } }); //Forget why use asynchronous flush Platform.runLater(new Runnable() { @Override public void run() { setGraphic(textField); } }); } } }
問題在於,這段程式碼在Java 7中可以正確執行,在Java8中則有顯示異常,會導致第一個空白行(行號2)重複顯示最後一個數據行(行號1)的內容。
經過除錯仔細分析其中可能的原因,終於找到問題所在:
JavaFX8中每個單元格都會對應一個獨立TextFieldTableCell物件,但是並不是每次重新整理都重新初始化一個新的物件,而是會優先使用已經存在的物件(也許是為了效能和記憶體優化),可嚴重的問題在於對於同一行號,並不保證每次拿到的都是同一個物件。
注:這個結論還沒有尋求官方資料的理論支援,而是自己總結的
由於我使用了非同步重新整理,而且每個單元格重新整理可能觸發多次,就導致了本來要重新整理行1,卻重新整理了行2情況(因為行2使用了行1的TextFieldTableCell物件) 。於是在非同步重新整理時,我需要增加行號的判斷即可:
Platform.runLater(new Runnable() { @Override public void run() { if (getIndex() == index) {//Important(Add in JDK 8) setGraphic(textField); } } });
不過也許一個單元格觸發多次重新整理本來就不合理...