我試圖按照MVC進行測試項目,所以我的模型應該完全獨立於我的視圖,但是我不知道如何更新Observable List在後臺線程中更新(它被給予Strings關於通過FTP上傳文件),以便消息出現在ListView中的UI上。從後臺線程更新可觀察列表的正確方法
我正在使用JavaFX並試圖讓我的程序儘可能鬆散耦合。在當前時刻,視圖包中的GUI取決於我的模型使用Platform.runLater(...)更新我的列表這一事實 - 據我所知,我的模型應該完全獨立於視圖,並且不應該「必須符合View的需求。
現在下面的代碼實際上「按預期工作」,它只是沒有正確建模,我不知道如何正確建模。一些最初的研究提出,我可能不得不使用觀察者和可觀察的 - 並在中間有另一個類作爲我的可觀察列表 - 但我不知道如何設置它。
所以我這是在後臺線程更新可觀察的名單:
private ObservableList<String> transferMessages;
public FTPUtil(String host, int port, String user, String pass) {
this.host = host;
this.port = port;
this.username = user;
this.password = pass;
transferMessages = FXCollections.observableArrayList();
connect();
}
public void upload(File src) {
System.out.println("Uploading: " + src.getName());
try {
if (src.isDirectory()) {
ftpClient.makeDirectory(src.getName());
ftpClient.changeWorkingDirectory(src.getName());
for (File file : src.listFiles()) {
upload(file);
}
ftpClient.changeToParentDirectory();
} else {
InputStream srcStream = null;
try {
addMessage("Uploading: " + src.getName());
srcStream = src.toURI().toURL().openStream();
ftpClient.storeFile(src.getName(), srcStream);
addMessage("Uploaded: " + src.getName() + " - Successfully.");
} catch (Exception ex) {
System.out.println(ex);
addMessage("Error Uploading: " + src.getName() + " - Speak to Administrator.");
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void addMessage(String message){
Platform.runLater(() -> transferMessages.add(0, message));
}
的FTPUtil類是我的模型。
我也有一個模型管理器類,這是什麼控制這FTPUtil類:
public class ModelManager {
private ObservableList<String> fileAndFolderLocations;
private FTPUtil ftpUtil;
public ModelManager(String host, int port, String user, String pass) {
ftpUtil = new FTPUtil(host, port, user, pass);
fileAndFolderLocations = FXCollections.observableArrayList();
}
public boolean startBackup() {
Task task = new Task() {
@Override
protected Object call() throws Exception {
System.out.println("I started");
ftpUtil.clearMessages();
for(String location : fileAndFolderLocations){
File localDirPath = new File(location);
ftpUtil.upload(localDirPath);
}
return null;
}
};
new Thread(task).start();
return true;
}
public void addFileOrFolder(String fileOrFolder){
if(!fileAndFolderLocations.contains(fileOrFolder)){
fileAndFolderLocations.add(fileOrFolder);
}
}
public boolean removeFileOrFolder(String fileOrFolder){
return fileAndFolderLocations.remove(fileOrFolder);
}
public ObservableList<String> getFilesAndFoldersList() {
return fileAndFolderLocations;
}
public ObservableList<String> getMessages() {
return ftpUtil.getMessages();
}
}
最後是我的GUI:
public class BackupController {
private Main main;
private ModelManager mm;
@FXML
private ListView<String> messagesList;
@FXML
void forceBackup(ActionEvent event) {
mm.startBackup();
}
public void initController(Main main, ModelManager mm) {
this.main = main;
this.mm = mm;
messagesList.setItems(mm.getMessages());
}
}
添加隔離層:保持模型無知的視圖(也就是不使用runLater),保持一個單獨的列表顯示項目,聆聽原始的變化nal消息並將它們傳播到fx線程上的單獨列表中(在這裏使用runLater) – kleopatra
@kleopatra嗨,就像隔離層一樣,你的意思是一個只保存另一個可觀察列表的類,或者擴展了一個可觀察列表 - >然後觀察我的模型(它應該是可觀察的),當它的列表發生變化時? – AntonyKimpton
與你現在做的相同的地方,BackgroundController對於任務看起來很好 – kleopatra