JavaFX WebView加载时阻塞NFC读卡及15秒超时取消方案咨询
问题根因
你现有代码的核心问题有3个:
- 每次调用
loadZeitdatenToWebview都会给WebEngine的状态属性新增一个监听器,旧的监听器不会被移除,导致状态变更时会触发多次回调,加载完成后会重复执行阻塞逻辑,把已经置为false的waitForData又改回true PauseTransition是局部变量,加载成功时无法主动停掉正在运行的超时任务,导致15秒内状态一直被标记为加载中- 状态判断逻辑错误:只要状态不是
RUNNING就设置waitForData=true,导致加载成功、失败、取消的状态都会重新开启阻塞和超时逻辑
修复方案
第一步:新增类成员变量
// 存储超时任务,方便加载完成后主动停止 private PauseTransition loadTimeoutTransition; // 加载阻塞标记,初始为false private boolean waitForData = false;
第二步:全局只添加一次WebView加载监听器
不要每次加载URL都重复加监听器,在界面初始化(比如initialize方法、控制器构造方法)阶段只加一次即可:
// 界面初始化阶段调用一次即可 private void initWebViewLoadListener() { WebEngine engine = webviewer.getEngine(); engine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> { // 1. 加载成功逻辑 if (newState == Worker.State.SUCCEEDED) { // 立刻停止超时任务 if (loadTimeoutTransition != null && loadTimeoutTransition.getStatus() == Animation.Status.RUNNING) { loadTimeoutTransition.stop(); } // 解除读卡阻塞 waitForData = false; zeiterfassungErfolgreich(); } // 2. 加载失败/取消逻辑 else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) { if (loadTimeoutTransition != null && loadTimeoutTransition.getStatus() == Animation.Status.RUNNING) { loadTimeoutTransition.stop(); } waitForData = false; labelReaderStatusInfo.setStyle("-fx-background-color:red; -fx-text-fill: white;"); labelReaderStatusInfo.setText("服务端连接失败,请重试"); } // 3. 开始加载逻辑,仅当状态切换到RUNNING时触发 else if (newState == Worker.State.RUNNING && oldState != Worker.State.RUNNING) { waitForData = true; zeiterfassungRunning(); // 开启15秒超时 startLoadTimeout(); } }); }
第三步:抽离超时逻辑,统一管理
private void startLoadTimeout() { // 先停掉之前可能还在运行的超时任务,避免冲突 if (loadTimeoutTransition != null && loadTimeoutTransition.getStatus() == Animation.Status.RUNNING) { loadTimeoutTransition.stop(); } loadTimeoutTransition = new PauseTransition(Duration.seconds(15)); loadTimeoutTransition.setOnFinished(event -> { Worker.State loadState = webviewer.getEngine().getLoadWorker().getState(); // 超时还在加载/调度中,直接终止 if (loadState == Worker.State.RUNNING || loadState == Worker.State.SCHEDULED) { webviewer.getEngine().executeScript("window.stop()"); webviewer.getEngine().getLoadWorker().cancel(); waitForData = false; labelReaderStatusInfo.setStyle("-fx-background-color:red; -fx-text-fill: white;"); labelReaderStatusInfo.setText("服务端连接超时,请重试"); } }); loadTimeoutTransition.play(); }
第四步:简化加载方法
private void loadZeitdatenToWebview(String uid) { webviewer.getEngine().load(httpHostforZeiterfassung + uid); }
第五步:修复字符串比较逻辑
Java中字符串内容比较不能用==,必须用equals,同时要先判空避免空指针:
String uid = nfcread.getValue(); if (uid != null && !uid.isEmpty() && !uid.equals("Error") && !uid.equals("Error no Card")) { // 原有读卡成功逻辑 }
效果说明
修改后网页加载成功/失败都会立刻停止超时任务,同时解除读卡阻塞,不需要等15秒超时结束,15秒超时仅针对网络异常、服务端无响应的场景。
内容的提问来源于stack exchange,提问作者loomy
相关产品推荐
相关产品推荐

