我希望有人可以提供帮助。我只是试图围绕观察者设计模式,线程以及如何将两者用于我正在进行的项目。
我目前需要在使用Java FX构建的媒体播放器上实现这两者。
我需要使用它们来更新我的listView(由我目录中的文件的getNames函数填充。我需要对我的歌曲文件夹进行任何更改以直接反映在GUI上。
是否有可能让一个正在运行的线程不断调用我的getNames函数(返回一个items变量),如果items变量有任何更改,那么我可以使用Observer模式通知我的GUI类更新其列表
我知道有一个线程可以不断访问该函数,但我只需要一些建议,如果它可以使用Observer模式来通知项目是否已更改!
我没有要显示的代码,因为我仍在试图弄清楚如何实现它。
有什么想法吗?
欣赏任何建议!谢谢:))
更新
经过相当长的一段时间,得到了这个线程和观察者模式。不需要WatchService。使用我的线程不断调用检查更改方法,然后如果方法返回通过Observer启动更新GUI。
答案 0 :(得分:0)
可以使用这种模式,你需要运行一个线程来监视文件夹上的文件更新并使这个线程安全使用eventQueue来运行你的线程 例如 java.awt.EventQueue.invokeLater或invokeAndWait
一旦线程检测到更改,那么您的观察者模式将更新GUI
希望这会有所帮助!!
答案 1 :(得分:0)
对此(IMO)的最佳方法是:
正如您所说,不幸的是,我们的讲师不允许我们使用WatchService",您可以使用下面示例代码中的方法,该方法是对FileSystem的主动调查。使用WatchService绝对是首选,因为它可以在JDK实现内部使用OS提供的文件监视服务。这些OS服务可以提供文件更改事件的通知,因此Java代码不需要主动轮询文件系统以进行更改。然而,在这种情况下,以下效率低下的工作可能足以完成工作......
代码所做的是在线程上生成JavaFX任务,该线程轮询文件系统并修改支持ListView的可观察列表以匹配文件系统上的文件。列表修改是在Platform.runLater调用内完成的,以确保对支持列表视图的列表的修改发生在JavaFX应用程序线程上,因此活动场景图不会从JavaFX应用程序线程中修改。
import javafx.application.*;
import javafx.collections.*;
import javafx.collections.transformation.SortedList;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;
import java.io.File;
import java.nio.file.*;
import java.util.Arrays;
import java.util.Comparator;
public class FileWatcher extends Application {
private static final Path WATCH_DIR = Paths.get(System.getProperty("user.dir"));
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
ObservableList<File> songFileList = FXCollections.observableArrayList();
SortedList<File> sortedSongFileList = new SortedList<>(
songFileList,
Comparator.comparing(File::getName)
);
ListView<File> songListView = new ListView<>();
songListView.setItems(sortedSongFileList);
songListView.setCellFactory(param -> new ListCell<File>() {
@Override
protected void updateItem(File item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
return;
}
setText(item.getName());
}
});
SongWatcher watcher = new SongWatcher(
WATCH_DIR, songFileList
);
Thread watcherThread = new Thread(watcher, "song-watcher");
watcherThread.setDaemon(true);
watcherThread.start();
Scene scene = new Scene(songListView);
stage.setScene(scene);
stage.show();
}
class SongWatcher extends Task<Void> {
private static final String SONG_EXTENSION = "mp3";
private static final long POLL_INTERVAL_MILLIS = 200;
private final Path directory;
private final ObservableList<File> songFiles;
SongWatcher(Path directory, ObservableList<File> songFiles) {
this.directory = directory;
this.songFiles = songFiles;
}
@Override
protected Void call() {
System.out.println("Started watching " + directory + " for song file changes.");
while (!isCancelled()) {
try {
Thread.sleep(POLL_INTERVAL_MILLIS);
} catch (InterruptedException e) {
if (isCancelled()) {
break;
}
Thread.currentThread().interrupt();
}
try {
if (!Files.isDirectory(directory)) {
throw new Exception("Watched directory " + directory + " is not a directory.");
}
File[] foundFiles =
directory
.toFile()
.listFiles(
(dir, name) -> name.endsWith(SONG_EXTENSION)
);
if (foundFiles == null) {
throw new Exception("Watched directory " + directory + " find files returned null (this is not expected).");
}
Platform.runLater(() -> {
// remove files from the song list which are no longer on the disk.
songFiles.removeIf(checkedFile ->
Arrays.binarySearch(foundFiles, checkedFile) < 0
);
// add any files which are on the disk which are not in the song list.
for (File file: foundFiles) {
if (!songFiles.contains(file)) {
songFiles.add(file);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void succeeded() {
System.out.println("Stopped watching " + directory + " for song file changes.");
}
@Override
protected void cancelled() {
System.out.println("Cancelled watching " + directory + " for song file changes.");
}
@Override
protected void failed() {
System.out.println("Failed watching " + directory + " for song file changes.");
if (getException() != null) {
getException().printStackTrace();
}
}
}
}