离盘确认次数:设置与使用代码位置

项目:ZhctWeightingTableYoukate(410 型优卡特称重台)
源码分支:zymy_ongoing
核验日期:2026-09-09
范围:配置定义、设置保存、首页加载及实际判断位置

3~10次新装默认7次升级兼容3次

核心结论:同一个“离盘确认次数”配置同时控制普通离盘、A03 原盘离开和 A02 补录盘清空。当前实现按连续空码回调次数判断,不是按 900ms/1200ms 的持续时间判断。

一、代码位置总览

环节文件行号作用
配置常量utils/Constants.java89配置键、默认值、兼容值和范围
范围策略antiescape/TrayRemovalConfirmationCountPolicy.java113~10校验及初始化
持久化antiescape/TrayRemovalConfirmationCountConfig.java16MMKV读取、修复和保存
设置页布局res/layout/activity_set.xml169设置项入口
设置页交互activity/SetActivity.java815输入、校验和保存
首页刷新activity/HomeActivity.java1875返回首页后重新加载配置
普通离盘activity/HomeActivity.java1473达到次数后执行扫码结束
A03 原盘移走activity/HomeActivity.java1497确认原未绑定盘移走
A02 补录盘清空antiescape/A02TrayClaimCodePolicy.java38允许同一餐盘再次查询

二、配置常量

app/src/main/java/com/cpt/zhct/weighting/utils/Constants.java:89

public static final String TRAY_REMOVAL_CONFIRMATION_COUNT =
        "tray_removal_confirmation_count";
public static final int TRAY_REMOVAL_CONFIRMATION_COUNT_DEFAULT_VALUE = 7;
public static final int TRAY_REMOVAL_CONFIRMATION_COUNT_LEGACY_VALUE = 3;
public static final int TRAY_REMOVAL_CONFIRMATION_COUNT_MIN_VALUE = 3;
public static final int TRAY_REMOVAL_CONFIRMATION_COUNT_MAX_VALUE = 10;

三、范围校验与初始化

antiescape/TrayRemovalConfirmationCountPolicy.java:11

public static boolean isValid(int value) {
    return value >= Constants.TRAY_REMOVAL_CONFIRMATION_COUNT_MIN_VALUE
            && value <= Constants.TRAY_REMOVAL_CONFIRMATION_COUNT_MAX_VALUE;
}

public static int normalize(int value) {
    return isValid(value)
            ? value
            : Constants.TRAY_REMOVAL_CONFIRMATION_COUNT_DEFAULT_VALUE;
}

public static int initialValue(boolean upgradedInstallation) {
    return upgradedInstallation
            ? Constants.TRAY_REMOVAL_CONFIRMATION_COUNT_LEGACY_VALUE
            : Constants.TRAY_REMOVAL_CONFIRMATION_COUNT_DEFAULT_VALUE;
}

四、MMKV读取与保存

antiescape/TrayRemovalConfirmationCountConfig.java:16

public static int get(Context context) {
    MmkvUtils mmkv = MmkvUtils.getInstance();
    if (!mmkv.containsKey(Constants.TRAY_REMOVAL_CONFIRMATION_COUNT)) {
        int initialValue = TrayRemovalConfirmationCountPolicy.initialValue(
                isUpgradedInstallation(context));
        mmkv.put(Constants.TRAY_REMOVAL_CONFIRMATION_COUNT, initialValue);
        return initialValue;
    }

    int storedValue = mmkv.get(Constants.TRAY_REMOVAL_CONFIRMATION_COUNT,
            Constants.TRAY_REMOVAL_CONFIRMATION_COUNT_DEFAULT_VALUE);
    int normalizedValue = TrayRemovalConfirmationCountPolicy.normalize(storedValue);
    if (storedValue != normalizedValue) {
        mmkv.put(Constants.TRAY_REMOVAL_CONFIRMATION_COUNT, normalizedValue);
    }
    return normalizedValue;
}

public static void save(int value) {
    if (!TrayRemovalConfirmationCountPolicy.isValid(value)) {
        throw new IllegalArgumentException(
                "tray removal confirmation count out of range");
    }
    MmkvUtils.getInstance().put(
            Constants.TRAY_REMOVAL_CONFIRMATION_COUNT, value);
}

五、设置页输入和保存

activity/SetActivity.java:815

private void showTrayRemovalConfirmationCountDialog() {
    final SingleInputDialog inputDialog = new SingleInputDialog(this,
            getString(R.string.set_item_tray_removal_confirmation_count_title),
            getString(R.string.set_item_tray_removal_confirmation_count_hint));

    inputDialog.setCurrentInputValue(
            TrayRemovalConfirmationCountConfig.get(this));

    // 输入完成后转换为整数并校验3~10
    if (!TrayRemovalConfirmationCountPolicy.isValid(value)) {
        showTrayRemovalConfirmationCountInvalidTip();
        return;
    }
    saveTrayRemovalConfirmationCount(value);
}

activity/SetActivity.java:847

private void saveTrayRemovalConfirmationCount(int value) {
    int previous = TrayRemovalConfirmationCountConfig.get(this);
    TrayRemovalConfirmationCountConfig.save(value);
    mTrayRemovalConfirmationCountView.setItemContent(
            getString(R.string.set_item_tray_removal_confirmation_count_value,
                    value));

    // 修改后写入防逃单配置日志
}

六、首页读取与同步

activity/HomeActivity.java:181

private int scanEmptyFrameCount = 0;

/** 普通离盘、A03 原盘离开和补录盘清空共用的连续空码确认次数。 */
private int mTrayRemovalConfirmationCount =
        Constants.TRAY_REMOVAL_CONFIRMATION_COUNT_DEFAULT_VALUE;

activity/HomeActivity.java:1875

private void refreshTrayRemovalConfirmationCount() {
    int configuredCount = TrayRemovalConfirmationCountConfig.get(this);
    if (mTrayRemovalConfirmationCount != configuredCount) {
        scanEmptyFrameCount = 0;
        mFirstEmptyScanElapsedMs = 0L;
    }
    mTrayRemovalConfirmationCount = configuredCount;
    mA02TrayClaimCodePolicy.setClearConfirmationCount(configuredCount);
}

该方法由 HomeActivity.onStart() 调用,从设置页返回首页后即可生效。

七、普通离盘判断

activity/HomeActivity.java:1473

private void handleEmptyScanCode() {
    if (TextUtils.isEmpty(mCurrentCode)) {
        return;
    }

    scanEmptyFrameCount++;
    if (scanEmptyFrameCount < mTrayRemovalConfirmationCount) {
        return;
    }

    scanEmptyFrameCount = 0;
    mFirstEmptyScanElapsedMs = 0L;
    scanCodeResult(2, "扫码结束!");
    updateTrayRequiredAlarmAfterTrayRemoval();
}

八、A03 原未绑定餐盘移走

activity/HomeActivity.java:1497

private void handleA03OriginalTrayRemoved(AntiEscapeAlarm alarm) {
    if (mA03OriginalTrayRemoved || alarm == null
            || alarm.getType() != AlarmType.TRAY_NOT_BOUND) {
        return;
    }

    scanEmptyFrameCount++;
    if (scanEmptyFrameCount < mTrayRemovalConfirmationCount) {
        return;
    }

    scanEmptyFrameCount = 0;
    mCurrentCode = "";
    mCurrentStaffInfo = null;
    mA03OriginalTrayRemoved = true;
    switchToBeforeFragment();
}

九、A02 补录餐盘清空

调用位置:activity/HomeActivity.java:1089

if (TextUtils.isEmpty(scanCode)) {
    if (mA02AlarmAction == A02AlarmAction.WAIT_TRAY_CLAIM) {
        if (mA02TrayClaimCodePolicy.onTrayCodeCleared()) {
            mA02TrayClaimCodePresent = false;
        }
    }
    return;
}

计数实现:antiescape/A02TrayClaimCodePolicy.java:38

public boolean onTrayCodeCleared() {
    emptyFrameCount++;
    if (emptyFrameCount >= clearConfirmationCount) {
        lastQueriedTrayCode = "";
        emptyFrameCount = 0;
        return true;
    }
    return false;
}

十、与硬件重复包的关系

当前风险:判断次数统计的是 APK 收到的空码回调。如果控制板把同一个扫码结果按 100ms×3 或 50ms×6 重复上报,重复空码包会分别增加计数。因此“3次”不一定代表3次独立的扫码头采样。

若后续落实约1秒的断码宽限,需要重点调整普通离盘和A03判断,并统一评估A02补录盘清空策略。

十一、核验边界