定期JavaFX服务
我希望在JavaFX应用程序中定期执行任务。该任务从远程流中提取数据 虽然我知道我可以使用下面建议的计时器: 我相信这应该可以使用JavaFX对象来完成。Javadoc中提到了指定一个自定义执行器(我想到这里),但是如何指定周期和延迟呢?理想情况下,这将使用服务通常的启动、重置、重新启动和状态绑定定期JavaFX服务,java,javafx-2,Java,Javafx 2,我希望在JavaFX应用程序中定期执行任务。该任务从远程流中提取数据 虽然我知道我可以使用下面建议的计时器: 我相信这应该可以使用JavaFX对象来完成。Javadoc中提到了指定一个自定义执行器(我想到这里),但是如何指定周期和延迟呢?理想情况下,这将使用服务通常的启动、重置、重新启动和状态绑定 public class MyFirstLineService extends Service<String> { private StringProperty url = n
public class MyFirstLineService extends Service<String> {
private StringProperty url = new SimpleStringProperty(this, "url");
public final void setUrl(String value) { url.set(value); }
public final String getUrl() { return url.get(); }
public final StringProperty urlProperty() { return url; }
public MyFirstLineService() {
setExecutor(new ScheduledThreadPoolExecutor());
}
protected Task createTask() {
final String _url = getUrl();
return new Task<String>() {
protected String call() throws Exception {
URL u = new URL(_url);
BufferedReader in = new BufferedReader(
new InputStreamReader(u.openStream()));
String result = in.readLine();
in.close();
return result;
}
};
}
}
公共类MyFirstLineService扩展服务{
私有StringProperty url=新的SimpleStringProperty(此“url”);
公共最终void setUrl(字符串值){url.set(值);}
公共最终字符串getUrl(){返回url.get();}
公共最终StringProperty urlProperty(){return url;}
公共MyFirstLineService(){
setExecutor(新的ScheduledThreadPoolExecutor());
}
受保护的任务createTask(){
最后一个字符串_url=getUrl();
返回新任务(){
受保护的字符串调用()引发异常{
URL u=新URL(_URL);
BufferedReader in=新的BufferedReader(
新的InputStreamReader(u.openStream());
字符串结果=in.readLine();
in.close();
返回结果;
}
};
}
}
我找到了一种方法,基于上面sarcan的评论
可以创建一个时间线对象,通常用于为UI元素设置动画,作为在FX应用程序线程上操作的计时器。使用此选项可以重新启动服务对象,然后服务对象在后台线程上执行长时间运行的操作,同时通过FX应用程序线程绑定保留属性访问和更新
例:
final MyFirstLineService svc=new MyFirstLineService();
最终持续时间oneFrameAmt=持续时间。秒(5);
最终关键帧oneFrame=新关键帧(oneFrameAmt,
新的EventHandler(){
@凌驾
公共无效句柄(ActionEvent evt){
svc.restart();
}
});
时间线计时器=TimelineBuilder.create()
.cycleCount(动画。不确定)
.关键帧(一帧)
.build();
timer.playFromStart();
在中请求了ScheduledService
跟踪器包括2.2分支中未包含的跟踪器。如果需要,您可以查看该源代码,看看它是否有助于改进您的解决方案。遇到同样的问题。
ScheduledThreadPoolExecutor
的示例可能是:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
Service s = new Service(){
@Override
protected Task<String> createTask() {
return new Task<String>() {
@Override
protected String call() throws Exception {
// code...
}
};
}
}
// created tasks shall be run in thread pool
s.setExecutor(executor);
// start the service the first time
s.start();
// restart the service every 5 seconds
s.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
// need runLater here since trigger needs to be in the javaFX thread
Platform.runLater(new Runnable() {
@Override
public void run() {
checker.restart();
}
});
}
}, 0, 5, TimeUnit.SECONDS);
}
ScheduledExecutorService executor=Executors.newScheduledThreadPool(5);
服务s=新服务(){
@凌驾
受保护的任务createTask(){
返回新任务(){
@凌驾
受保护的字符串调用()引发异常{
//代码。。。
}
};
}
}
//创建的任务应在线程池中运行
s、 设定执行人(执行人);
//第一次启动服务
s、 start();
//每5秒重新启动一次服务
s、 scheduleWithFixedDelay(新的可运行(){
@凌驾
公开募捐{
//需要稍后在此运行,因为触发器需要位于javaFX线程中
Platform.runLater(新的Runnable(){
@凌驾
公开募捐{
checker.restart();
}
});
}
},0,5,时间单位为秒);
}
可以使用
计时器解决,但随后您失去了JavaFX数据绑定功能(正如您已经提到的)。期待Java8 似乎强迫自己使用服务类会使事情变得更复杂。是否有ScheduledThreadPoolExecutor不提供的服务提供给您?在这之前,您必须同意Andy的意见,为什么首先要使用服务
?如果您确定这就是您想要的,那么使用计时器
定期重新启动服务
不是更好的选择吗?服务对象可以直接与FX应用程序线程交互。通过尝试实现ScheduledThreadPoolExecutor增加的复杂性节省了创建代理对象以将数据移入和移出服务的复杂性(即,来自TextField控件的流参数、到TextField控件的流输出)。我当然可以使用代理对象来执行执行器,但我认为这样会更好。sarcan-我尝试使用计时器重新启动服务,但遇到异常,因为重新启动发生在FX应用程序线程之外。这个答案和我的答案实际上都没有回答这个问题。但这显然是最合适的解决方案。
ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
Service s = new Service(){
@Override
protected Task<String> createTask() {
return new Task<String>() {
@Override
protected String call() throws Exception {
// code...
}
};
}
}
// created tasks shall be run in thread pool
s.setExecutor(executor);
// start the service the first time
s.start();
// restart the service every 5 seconds
s.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
// need runLater here since trigger needs to be in the javaFX thread
Platform.runLater(new Runnable() {
@Override
public void run() {
checker.restart();
}
});
}
}, 0, 5, TimeUnit.SECONDS);
}