Android应用写入NTAG215 NFC标签异常报错求助
NFC标签写入崩溃问题分析与解决方案
问题原因分析
- 空指针异常未捕获:当NTAG215未被NDEF格式化时,
Ndef.get(tag)会返回null,后续调用ndef.connect()会抛出NullPointerException,但你的代码只捕获了IOException和FormatException,导致应用直接崩溃,无法触发错误提示Toast。 - ForegroundDispatch过滤优先级低:
ACTION_TAG_DISCOVERED是NFC Intent中优先级最低的,系统可能优先触发其他应用的NFC处理逻辑,导致myTag无法被正确赋值。 - 写入逻辑不完善:没有检查标签的NDEF支持状态,也未处理标签连接失败、写入中断等边缘情况。
代码优化建议
核心修改点
- 增加
NullPointerException捕获,处理NDEF不可用的标签 - 替换
enableForegroundDispatch为更可靠的enableReaderMode,避免Intent优先级问题 - 完善写入逻辑,支持格式化未NDEF初始化的标签
- 使用try-with-resources确保NFC资源正确释放
- 优化Toast显示的线程安全性
修改后的完整代码
NfcAdapter adapter; Tag myTag; Context ctx; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ctx = this; Button btnWrite = findViewById(R.id.button); final TextView name = findViewById(R.id.name); btnWrite.setOnClickListener(v -> { try { if (myTag == null) { showToast(getString(R.string.error_detected)); return; } write(name.getText().toString(), myTag); showToast(getString(R.string.ok_writing)); } catch (NullPointerException e) { showToast(getString(R.string.error_ndef_not_supported)); e.printStackTrace(); } catch (IOException e) { showToast(getString(R.string.error_writing)); e.printStackTrace(); } catch (FormatException e) { showToast(getString(R.string.error_writing)); e.printStackTrace(); } }); adapter = NfcAdapter.getDefaultAdapter(this); } private void write(String text, Tag tag) throws IOException, FormatException { Ndef ndef = Ndef.get(tag); if (ndef != null) { // 处理已NDEF格式化的标签 ndef.connect(); try (ndef) { // try-with-resources自动关闭连接 NdefMessage message = new NdefMessage(new NdefRecord[]{createRecord(text)}); if (!ndef.isWritable()) { throw new IOException("Tag is not writable"); } if (ndef.getMaxSize() < message.toByteArray().length) { throw new IOException("Text too long for tag"); } ndef.writeNdefMessage(message); } } else { // 格式化未NDEF初始化的标签并写入 NdefFormatable formatable = NdefFormatable.get(tag); if (formatable != null) { formatable.connect(); try (formatable) { NdefMessage message = new NdefMessage(new NdefRecord[]{createRecord(text)}); formatable.format(message); } } else { throw new NullPointerException("Tag does not support NDEF"); } } } private NdefRecord createRecord(String text) throws UnsupportedEncodingException { String lang = "en"; byte[] textBytes = text.getBytes("UTF-8"); // 改用UTF-8支持多语言字符 byte[] langBytes = lang.getBytes("US-ASCII"); int langLength = langBytes.length; int textLength = textBytes.length; byte[] payload = new byte[1 + langLength + textLength]; payload[0] = (byte) langLength; System.arraycopy(langBytes, 0, payload, 1, langLength); System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength); return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload); } // 使用enableReaderMode替代ForegroundDispatch,逻辑更稳定 @Override protected void onResume() { super.onResume(); if (adapter != null) { adapter.enableReaderMode(this, tag -> { myTag = tag; runOnUiThread(() -> showToast(getString(R.string.ok_detection) + tag.toString())); }, NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null); } } @Override protected void onPause() { super.onPause(); if (adapter != null) { adapter.disableReaderMode(this); } } private void showToast(String message) { runOnUiThread(() -> Toast.makeText(ctx, message, Toast.LENGTH_LONG).show()); }
优化说明
- enableReaderMode优势:直接通过回调获取Tag,避免Intent分发的优先级问题,逻辑更简洁可靠
- 兼容未格式化标签:新增
NdefFormatable处理逻辑,支持对未初始化的NTAG215进行格式化写入 - 完善异常覆盖:新增空指针、标签不可写、内容过长等异常处理,确保崩溃场景都能触发错误提示
- 资源安全释放:使用try-with-resources自动关闭NFC连接,避免资源泄漏
- 多语言支持:文本编码改用UTF-8,支持中文、特殊字符等非ASCII内容
适配标签技术推荐
- NTAG215:当前选择完全适配,504字节容量足够存储文本、URL等轻量数据,成本低,是入门NFC开发的首选
- NTAG216:如果需要更大存储(888字节),可以升级,适合存储多行文本、小型JSON等内容
- MIFARE Ultralight C:带有UID加密功能,适合需要简单防伪的场景,同样支持NDEF格式
内容的提问来源于stack exchange,提问作者Student Progg
相关产品推荐
相关产品推荐

