8. 用户取消处理:用户主动取消、系统取消、重试机制、友好的UI提示

嗯,这一章咱们聊聊取消处理。你可能会想,取消不就是点一下“取消”按钮吗?有什么好讲的?

其实不然。我在项目里见过太多因为取消处理不当导致的崩溃、ANR,甚至用户直接给一星差评。说白了,取消处理是用户体验的最后一道防线,处理不好,前面所有努力都白费。

8.1 用户主动取消 vs 系统取消

先分清楚两种取消场景:

取消类型 触发方式 典型场景
用户主动取消 用户点击“取消”按钮或按返回键 用户突然不想验证了,或者误触了验证流程
系统取消 系统内部中断(如锁屏、来电、低内存) 验证过程中突然来电话,或者系统资源紧张被回收

我个人习惯把这两种情况分开处理。为什么呢?因为用户主动取消,通常意味着用户有明确的意图;而系统取消,用户可能还一脸懵,需要更友好的引导。

核心原则:用户主动取消,尊重用户选择,直接退出流程;系统取消,保留上下文,给用户重试的机会。

8.2 用户主动取消的处理

用户点击取消,或者按返回键,这时候应该做什么?

  • 立即停止认证:调用 BiometricPrompt.cancelAuthentication(),释放系统资源。
  • 不要弹确认对话框:用户已经明确要取消,再弹“你确定要取消吗?”只会让用户烦躁。我见过有些App这么干,结果用户更生气了。
  • 回调处理:onAuthenticationError() 中捕获 ERROR_USER_CANCELED(错误码13),执行退出逻辑。
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
    if (errorCode == BiometricPrompt.ERROR_USER_CANCELED) {
        // 用户主动取消,直接关闭页面
        finish();
    } else {
        // 其他错误,走系统取消逻辑
        handleSystemCancel(errorCode, errString);
    }
}

小技巧:如果用户连续多次主动取消,可以考虑记录一下次数。我曾经遇到一个用户,因为指纹识别总失败,连续取消了10次。后来我们加了一个“遇到问题?试试密码登录”的入口,用户满意度提升了不少。

8.3 系统取消的处理

系统取消的情况比较复杂。常见的系统取消原因包括:

  • 锁屏:用户按了电源键,屏幕关闭。
  • 来电:电话呼入,系统抢占前台。
  • 低内存:系统回收了BiometricPrompt的资源。
  • 超时:用户长时间未操作,系统自动取消。

对于系统取消,我的建议是:不要直接退出。用户可能只是暂时离开,或者被其他事情打断。你应该保留当前页面,并显示一个友好的提示。

@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
    switch (errorCode) {
        case BiometricPrompt.ERROR_LOCKOUT:
            // 锁定,需要等待
            showLockoutMessage(errString);
            break;
        case BiometricPrompt.ERROR_TIMEOUT:
            // 超时,提示用户重新尝试
            showRetryPrompt("验证超时,请重试");
            break;
        case BiometricPrompt.ERROR_CANCELED:
            // 系统取消(非用户主动),保留页面
            showMessage("验证已取消,可重新尝试");
            break;
        default:
            // 其他系统错误,记录日志
            Log.w("Biometric", "系统取消: " + errorCode + " - " + errString);
            showRetryPrompt("系统异常,请重试");
    }
}

注意:系统取消时,不要自动重新开始认证。我曾经犯过这个错误——系统取消后立刻自动重试,结果用户还没反应过来,又取消了,陷入死循环。正确的做法是:显示一个重试按钮,让用户主动点击。

8.4 重试机制的设计

重试机制是取消处理的核心。设计得好,用户会觉得“这个App很智能”;设计得不好,用户会觉得“这个App在耍我”。

我总结了几条重试原则:

  1. 有限重试:不要无限重试。一般3次失败后,引导用户使用其他方式(如密码)。
  2. 冷却时间:连续失败后,增加重试间隔。比如第一次失败立即重试,第二次等待2秒,第三次等待5秒。
  3. 状态保留:重试时不要重置整个页面,只重置认证状态。用户输入的其他信息(如果有)应该保留。
private int retryCount = 0;
private static final int MAX_RETRIES = 3;

private void handleRetry() {
    if (retryCount < MAX_RETRIES) {
        retryCount++;
        // 显示重试按钮,用户点击后重新启动认证
        showRetryButton("重试 (" + (MAX_RETRIES - retryCount + 1) + "/" + MAX_RETRIES + ")");
    } else {
        // 超过最大重试次数,引导用户使用其他方式
        showAlternativeLoginOption();
    }
}

避坑指南:我曾经在重试时忘记重置 CancellationSignal,导致第二次认证直接失败。记住:每次重新认证前,必须创建新的 BiometricPrompt 实例和新的 CancellationSignal

8.5 友好的UI提示

UI提示是取消处理的最后一步,也是最容易被忽视的一步。很多App在取消时只显示一个Toast“验证已取消”,然后就没了。这其实不够。

我建议的UI提示策略:

  • 明确原因:告诉用户为什么取消。比如“验证超时,请重试”比“验证失败”好得多。
  • 提供下一步:取消后不要留用户在那里发呆。提供“重试”、“使用密码”、“联系客服”等选项。
  • 保持一致性:UI风格与App整体保持一致。不要突然弹出一个系统风格的Dialog,显得很突兀。

下面是一个友好的UI提示示例:

private void showRetryPrompt(String message) {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("验证中断")
           .setMessage(message + "\n您可以重试,或使用其他方式登录。")
           .setPositiveButton("重试", (dialog, which) -> {
               startBiometricAuthentication();
           })
           .setNegativeButton("使用密码", (dialog, which) -> {
               navigateToPasswordLogin();
           })
           .setCancelable(false)  // 防止用户再次取消
           .show();
}

个人经验:在UI提示中,尽量使用“您”而不是“你”。虽然只是一个字的差别,但用户感知到的尊重感完全不同。另外,按钮文字用“重试”而不是“确定”,因为“确定”太模糊了,用户不知道确定什么。

8.6 知识体系流程图

下面这张图总结了取消处理的整体逻辑,你可以对照着看:

取消处理流程 认证开始 取消发生? (onAuthenticationError) 用户主动取消 (ERROR_USER_CANCELED) 直接退出流程 系统取消 (超时/锁屏/来电等) 保留页面,显示提示 结束 重试次数 < 3? 显示重试按钮 引导使用其他方式 最终结束

嗯,这张图把整个取消处理的脉络理清楚了。你想想看,从认证开始,到取消发生,再到分支处理,最后到重试或结束,每一步都有对应的代码和UI策略。

8.7 总结

取消处理看似简单,但细节很多。我最后再强调几点:

  • 区分主动取消和系统取消,处理方式完全不同。
  • 重试要有限制,不要无限循环。
  • UI提示要友好,告诉用户原因,并提供下一步操作。
  • 记得重置状态,特别是 CancellationSignalBiometricPrompt 实例。

最后提醒:千万不要在 onAuthenticationError 中做耗时操作,比如网络请求。这个回调是在主线程执行的,阻塞会导致ANR。如果你需要记录日志或上报数据,请使用异步方式。

好了,这一章就到这里。取消处理是用户体验的“兜底”环节,做好了,用户会觉得你的App很可靠;做不好,用户会觉得你的App很“脆弱”。希望你能把这些经验用在自己的项目里。

公众号:蓝海资料掘金营,微信deep3321