我正在尝试创建一个Internet Checker类,该类将检查与某个URL的连接并相应地更新status属性。为了避免ui冻结,我想使用一个线程,并使用计时器在一定间隔后重新检查。问题是时间轴关键帧中的CHECK方法调用仍从FX线程调用。如何在线程内使用时间线?
代码:
*
答案 0 :(得分:2)
由于您需要执行与 JavaFX Application Thread 通信的定期 background 任务,因此最好使用ScheduledService
。此类使用开发人员可以定义的Executor
定期执行{new} Task
。请注意,ScheduledService
扩展了javafx.concurrent.Service
。
这是实现此功能所需的基本示例:
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
public class ConnectionStatusService extends ScheduledService<Status> {
// Property allows you to change the "baseUrl" between executions
private final StringProperty baseUrl = new SimpleStringProperty(this, "baseUrl");
// property getter and setters omitted...
@Override
protected Task<Status> createTask() {
// creates a new Task and gives the current "baseUrl"
// as an argument. This is called every cycle
return new ConnectionStatusTask(getBaseUrl());
}
private static class ConnectionStatusTask extends Task<Status> {
// A Task is a one-shot thing and its initial state should be
// immutable (or at least encapsulated from external modification).
private final String baseUrl;
private ConnectionStatusTask(String baseUrl) {
this.baseUrl = baseUrl;
}
@Override
protected Status call() throws Exception {
// Do what you need to determine connection status
return computedStatus;
}
}
}
然后,您将侦听/绑定到lastValue
属性。
public void initService() {
ConnectionStatusService service = new ConnectionStatusService();
service.setBaseUrl(/* your URL */);
service.setPeriod(Duration.seconds(1)); // run every 1 seconds
service.lastValueProperty().addListener(/* your listener */); // or bind to this property
// you may also want to add EventHandlers/Listeners to handle when the
// service fails and such.
service.start();
}
请务必注意lastValue
属性而不是value
属性。原因在lastValue
的Javadoc中给出:
最后一次成功计算的值。在每次迭代中, 与任何其他情况一样,ScheduledService的“值”将重置为null 其他服务。但是,“ lastValue”将设置为最大 最近成功计算的值,即使是在迭代中也是如此。它是 但是,只要您手动调用重置或重新启动,就可以重置。
我建议阅读Task
,Service
和ScheduledService
的Javadoc了解更多信息。所有这三个类都实现了javafx.concurrent.Worker
接口。
答案 1 :(得分:1)
您只希望在JavaFX应用程序线程上执行一条语句,即status.set(status);
。由于您打算在运行此语句之间有一定的延迟,因此可以简单地使用Platform.runLater
来完成此操作。
对于重复执行检查:ScheduledExecutorService
是为此目的而设计的。
public class InternetChecker implements Runnable {
private final String baseUrl;
/***Properties***/
// use readonly wrapper here to restrict outside access to the property
private final ReadOnlyObjectWrapper<Status> status = new ReadOnlyObjectWrapper<>(Status.ACTIVE);
/****************************************************************
********** CONSTRUCTORS ************
****************************************************************/
public InternetChecker(String baseUrl) {
this.baseUrl = baseUrl;
}
/*******************************
* Will check if there is an internet connection present
* and update the status accordingly
*******************************/
@Override
public void run() {
// Check if base internet connection
// is working, if it is we continue
// to see if domain connection is working
try {
if ("127.0.0.1".equals(InetAddress.getLocalHost().getHostAddress())) {
setStatus(Status.INTERNET_DISCONNECTED);
return;
}
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
// Check if base domain connection is working
try {
final URL url = new URL(baseUrl);
final URLConnection conn = url.openConnection();
conn.connect();
conn.getInputStream().close();
setStatus(Status.ACTIVE);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} catch (IOException e) {
setStatus(Status.BASE_URL_UNREACHABLE);
}
}
/****************************************************************
********** ACCESSORS ************
****************************************************************/
public Status getStatus() {
return status.get();
}
public ReadOnlyObjectProperty<Status> statusProperty() {
return status.getReadOnlyProperty();
}
private void setStatus(final Status status) {
Platform.runLater(() -> this.status.set(status));
}
/*******************************
* ACTIVE (Base url reachable)
* BASE_URL_UNREACHABLE (Internet available, but base url is unreachable)
* INTERNET_DISCONNECTED (Internet is not available)
********************************/
public enum Status {
ACTIVE,
BASE_URL_UNREACHABLE,
INTERNET_DISCONNECTED;
}
}
InternetChecker checker = new InternetChecker(url);
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
// use delay here to avoid race condition
executorService.scheduleAtFixedDelay(checker, 0, millisCheckInterval, TimeUnit.MILLISECONDS);
请注意,您需要“手动”关闭服务或使用ThreadFactory
返回的守护线程:
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(r -> {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
});