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

执行NFC长耗时操作时频繁触发ANR问题排查求助

NFC读取频繁ANR的问题分析与修复

核心问题点

1. 耗时NFC操作被错误放到主线程执行

CardPairingActivity.continueExec()方法中,使用默认Handler将API.cardAuthenticate()和API.readAndStoreNFCUserProfileData()这类耗时NFC操作抛回主线程执行,直接阻塞UI线程导致ANR。默认Handler创建时会绑定当前线程的Looper,这里handler在Activity主线程初始化,所以post的Runnable会在主线程运行。

2. 同时启用两种NFC监听模式引发冲突

代码中同时启用了Foreground Dispatch和Reader Mode两种NFC监听机制:

  • onCreate和onResume中同时调用nfcAdapter.enableForegroundDispatch()和nfcAdapter.enableReaderMode()
  • 两种模式会同时监听NFC事件,导致回调逻辑混乱,可能引发资源竞争或线程阻塞。

3. StrictMode被全局禁用,主线程违规操作无法被检测

代码中设置StrictMode.ThreadPolicy.Builder().permitAll(),关闭了Android对主线程耗时操作的检测,导致主线程执行NFC操作的问题无法被及时发现,掩盖了ANR的根本原因。

4. 弹窗关闭后直接触发主线程耗时操作

AlertCallbackDialog.onDismiss()方法中直接调用continueExec(),而continueExec()又将耗时操作放回主线程,再次阻塞UI线程。

5. 静态变量持有Activity上下文,可能引发内存泄漏

CardPairingActivity中的myContext是静态变量,持有Activity实例,当Activity销毁时无法被GC回收,长期运行会导致内存泄漏,间接引发ANR。

修复方案

1. 将耗时NFC操作移至后台线程

修改continueExec(),用新线程执行耗时操作,仅在需要更新UI时通过Handler回调主线程:

@RequiresApi(api = Build.VERSION_CODES.O)
public static void continueExec() {
    // 新线程执行耗时NFC操作
    new Thread(() -> {
        System.out.println("Authenticating to card ...");
        System.out.println("Card User Role: " + (int) role);
        System.out.println("Card Username: " + username);
        System.out.println("Card Secret: " + password);

        try {
            if (API.cardAuthenticate(Constants.USER_KEYMAN, username, password.toCharArray())) {
                // 执行大量数据读取
                API.readAndStoreNFCUserProfileData();
                
                // 成功后在主线程更新UI
                new Handler(Looper.getMainLooper()).post(() -> {
                    // 这里处理跳转、成功提示等UI操作
                });
            } else {
                System.out.println("[ERR] Card Login FAILED ...");
                int tries = API.adminCardLoginTriesRemaining(role, null);
                
                // 失败弹窗必须在主线程显示
                new Handler(Looper.getMainLooper()).post(() -> {
                    Context context = myContextRef.get();
                    if (context != null) {
                        if (tries != -1) {
                            SharedResource.showNotificationDialog("Card Pairing Failed", "Card Login Failed. \r\nLogin Retries Left: " + tries, "OK", context, MainActivity.class);
                        } else {
                            SharedResource.showNotificationDialog("Card Pairing Failed", "Card Login Failed.", "OK", context, MainActivity.class);
                        }
                    }
                });
            }
            // 操作完成后关闭NFC连接
            if (SharedResource.getIsoDep() != null) {
                try {
                    SharedResource.getIsoDep().close();
                    SharedResource.setIsoDep(null);
                } catch (IOException e) {
                    Log.e("ATHTAG", "Error closing NFC connection", e);
                }
            }
        } catch (Exception e) {
            Log.e("ATHTAG", "Error during card operation", e);
            // 错误提示在主线程显示
            new Handler(Looper.getMainLooper()).post(() -> {
                Context context = myContextRef.get();
                if (context != null) {
                    SharedResource.showNotificationDialog("Error", "Card operation failed", "OK", context, MainActivity.class);
                }
            });
        }
    }).start();
}

2. 只保留一种NFC监听模式

选择Reader Mode(更适配ISO-14443-4标签场景),移除Foreground Dispatch相关代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_card_pairing);

    // 用弱引用持有上下文,避免内存泄漏
    myContextRef = new WeakReference<>(this);
    callBack = new PairingCallBack();
    callBack.setContext(this);

    NfcManager nfcManager = (NfcManager) getSystemService(Context.NFC_SERVICE);
    nfcAdapter = NfcAdapter.getDefaultAdapter(this);
    if (nfcAdapter != null) {
        nfcAdapter.enableReaderMode(this, callBack, READER_FLAGS, null);
        System.out.println("NFC Adapter ready ...");
    }

    if (nfcManager != null) {
        System.out.println("NFC Manager ready ...");
    }
}

@Override
protected void onResume() {
    super.onResume();
    if (nfcAdapter != null) {
        nfcAdapter.enableReaderMode(this, callBack, READER_FLAGS, null);
    }
}

3. 移除StrictMode全局禁用代码

删除StrictMode.ThreadPolicy相关配置,让Android系统自动检测主线程的耗时操作,帮助快速定位问题。

4. 用弱引用持有Activity上下文

替换静态myContext为弱引用,避免内存泄漏:

// 替换静态myContext为弱引用
private static WeakReference<Context> myContextRef;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 19:47:02