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

Android中如何让AlertDialog即时显示NFC卡片挑战码?

问题原因

你的onNewIntent方法运行在主线程中,虽然你用handler.post()触发AlertDialog显示,但后续的API.cardAuthenticate()等NFC认证操作同样在主线程执行,这些耗时操作会阻塞UI线程,导致Dialog渲染被延迟,直到所有主线程任务完成后才会显示。

解决方案

要实现Dialog即时显示并等待用户验证,需要把耗时的NFC认证逻辑移到后台线程,同时让Dialog的交互触发后续流程:

1. 移除主线程阻塞的StrictMode设置

首先删掉onCreate里的StrictMode代码,它允许主线程执行耗时操作,是UI阻塞的根源之一:

// 移除这段代码
if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}

2. 用后台线程处理NFC通信,主线程显示Dialog

通过Thread+runOnUiThread分离UI与耗时操作,确保Dialog即时显示并等待用户确认后再执行认证:

@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);

    System.out.println("Doing onNewIntent() ...");

    Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    boolean hasIsoDep = false;

    if (tag != null) {
        System.out.println("New tag found !!!");
        System.out.println("Tag ID: " + BinUtils.toHexString(tag.getId()));
        for (String tagTech : tag.getTechList()) {
            System.out.println("Tech: " + tagTech);
            if (tagTech.equals("android.nfc.tech.IsoDep")) {
                hasIsoDep = true;
            }
        }
    } else {
        System.out.println("No new tag found !!!");
    }

    if (hasIsoDep) {
        // 耗时NFC操作放到后台线程
        new Thread(() -> {
            IsoDep iso14443 = null;
            try {
                iso14443 = IsoDep.get(tag);
                iso14443.connect();
                SharedResource.setIsoDep(iso14443);
                System.out.println("Selecting KeyVault applet ...");
                HashMap<String, Object> result = API.adminInit();
                boolean isSuccess = (boolean) result.get("Success");

                if (isSuccess) {
                    String toShow = (String) result.get("Message");
                    if (toShow != null) {
                        System.out.println("Showing Secure Session popup ...");
                        // 主线程显示Dialog,等待用户确认
                        runOnUiThread(() -> {
                            AlertDialog.Builder builder = new AlertDialog.Builder(CardPairingActivity.this);
                            builder.setTitle("Secure Card Session");
                            builder.setMessage(toShow);
                            builder.setPositiveButton("确认", (dialog, which) -> {
                                // 用户确认后,后台继续执行认证
                                new Thread(() -> {
                                    try {
                                        if (API.cardAuthenticate(Constants.USER_KEYMAN, username, password.toCharArray())) {
                                            System.out.println("[INF] Card Login SUCCESS ...");
                                            // 登录成功的UI操作回到主线程
                                            runOnUiThread(() -> {
                                                // 示例:跳转至成功页面
                                            });
                                        } else {
                                            System.out.println("[ERR] Card Login FAILED ...");
                                            int tries = API.adminCardLoginTriesRemaining(role, null);
                                            runOnUiThread(() -> {
                                                if (tries != -1) {
                                                    SharedResource.showNotificationDialog("Card Pairing Failed", "Card Login Failed. \r\nLogin Retries Left: " + tries, "OK", CardPairingActivity.this, MainActivity.class);
                                                } else {
                                                    SharedResource.showNotificationDialog("Card Pairing Failed", "Card Login Failed.", "OK", CardPairingActivity.this, MainActivity.class);
                                                }
                                            });
                                        }
                                    } catch (Exception ex) {
                                        Log.e("ATHTAG", "Error during authentication", ex);
                                    } finally {
                                        try {
                                            if (iso14443 != null && iso14443.isConnected()) {
                                                iso14443.close();
                                            }
                                        } catch (IOException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                }).start();
                            });
                            AlertDialog alert = builder.create();
                            alert.setCancelable(false); // 禁止用户取消,确保完成验证
                            alert.show();
                        });
                    }
                } else {
                    System.out.println("[ERR] Failed to select applet !!!");
                }
            } catch (Exception ex) {
                Log.e("ATHTAG", "Error found during tag comms", ex);
            } finally {
                try {
                    if (iso14443 != null && iso14443.isConnected()) {
                        iso14443.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

3. 核心改进点

  • UI与耗时操作分离:所有NFC通信、认证逻辑放在后台线程,主线程仅处理Dialog显示和用户交互,避免UI阻塞。
  • 用户交互驱动流程:Dialog添加确认按钮,只有用户点击后才执行后续认证,保证用户有足够时间验证挑战码。
  • 线程安全保障:所有UI操作通过runOnUiThread执行,避免跨线程操作UI的异常。
  • 资源安全回收:通过finally块确保NFC连接被正确关闭,避免资源泄漏。

内容的提问来源于stack exchange,提问作者thotheolh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 22:32:11