You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX WebView加载时阻塞NFC读卡及15秒超时取消方案咨询

问题根因

你现有代码的核心问题有3个:

  1. 每次调用loadZeitdatenToWebview都会给WebEngine的状态属性新增一个监听器,旧的监听器不会被移除,导致状态变更时会触发多次回调,加载完成后会重复执行阻塞逻辑,把已经置为false的waitForData又改回true
  2. PauseTransition是局部变量,加载成功时无法主动停掉正在运行的超时任务,导致15秒内状态一直被标记为加载中
  3. 状态判断逻辑错误:只要状态不是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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 04:27:00