Android读取NFC卡片空指针异常代码修复请求
修复NFC读取时的空指针崩溃问题
崩溃原因分析
控制台日志显示空指针异常发生在MainActivity.java:126,对应buildTagViews方法中访问msgs[0]的代码。核心问题是该方法的条件判断逻辑完全写反:
if (msgs == null || msgs.length == 0){ // 尝试访问msgs[0],必然触发空指针 }
当检测到的NFC标签没有NDEF数据,或者rawMsgs为空时,msgs会是null或空数组,此时代码反而尝试读取数组元素,直接导致崩溃。
修复方案
1. 修正buildTagViews核心逻辑
将条件判断改为有效数据分支,并添加无数据的友好处理:
private void buildTagViews(NdefMessage[] msgs){ if (msgs != null && msgs.length > 0){ String text = ""; NdefRecord record = msgs[0].getRecords()[0]; byte[] payload = record.getPayload(); String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; int languageCodeLength = payload[0] & 0x3F; try { text = new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding); } catch (UnsupportedEncodingException e) { Log.e("UnsupportedEncoding", e.toString()); } Log.d("myTag", text); nfc_contents.setText("NFC内容: " + text); } else { // 处理无NDEF数据的标签 nfc_contents.setText("该NFC标签无可用NDEF数据"); Log.d("myTag", "未找到NDEF消息"); } }
2. 优化readfromIntent方法(兼容更多场景)
添加从Tag对象直接读取NDEF数据的逻辑,兼容Intent中未携带NDEF消息的情况:
private void readfromIntent(Intent intent){ String action = intent.getAction(); if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action) || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)){ Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); NdefMessage[] msgs = null; // 尝试从Tag对象读取NDEF数据 Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); if (tag != null) { try { Ndef ndef = Ndef.get(tag); if (ndef != null) { ndef.connect(); msgs = ndef.getNdefMessage() != null ? new NdefMessage[]{ndef.getNdefMessage()} : null; ndef.close(); } } catch (Exception e) { Log.e("NDEF Read Error", e.toString()); } } // 优先使用Intent中的数据 if (rawMsgs != null && rawMsgs.length > 0) { msgs = new NdefMessage[rawMsgs.length]; for (int i = 0; i < rawMsgs.length; i++) { msgs[i] = (NdefMessage) rawMsgs[i]; } } buildTagViews(msgs); } }
修复后的完整MainActivity代码
public class MainActivity extends AppCompatActivity { public static final String Error_Detected = "未检测到NFC标签"; public static final String Write_Success = "写入成功!"; public static final String Write_Error = "写入失败,请重试!"; NfcAdapter nfcAdapter; PendingIntent pendingIntent; IntentFilter writingTagFilters[]; boolean writeMode; Tag myTag; Context context; TextView edit_message; TextView nfc_contents; Button ActivateButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); edit_message = findViewById(R.id.edit_message); nfc_contents = findViewById(R.id.nfc_contents); ActivateButton = findViewById(R.id.ActivateButton); context = this; ActivateButton.setOnClickListener(view -> { try { if(myTag == null){ Toast.makeText(context, Error_Detected, Toast.LENGTH_LONG).show(); }else { write("PlainTest|" + edit_message.getText().toString(), myTag); Toast.makeText(context, Write_Success, Toast.LENGTH_LONG).show(); } } catch (IOException | FormatException e) { Toast.makeText(context, Write_Error, Toast.LENGTH_LONG).show(); e.printStackTrace(); } }); nfcAdapter = NfcAdapter.getDefaultAdapter(this); if(nfcAdapter == null){ Toast.makeText(this,"该设备不支持NFC",Toast.LENGTH_LONG).show(); finish(); } readfromIntent(getIntent()); pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE); IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED); tagDetected.addCategory(Intent.CATEGORY_DEFAULT); writingTagFilters = new IntentFilter[] { tagDetected }; } private void readfromIntent(Intent intent){ String action = intent.getAction(); if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action) || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)){ Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); NdefMessage[] msgs = null; // 尝试从Tag对象读取NDEF数据 Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); if (tag != null) { try { Ndef ndef = Ndef.get(tag); if (ndef != null) { ndef.connect(); msgs = ndef.getNdefMessage() != null ? new NdefMessage[]{ndef.getNdefMessage()} : null; ndef.close(); } } catch (Exception e) { Log.e("NDEF Read Error", e.toString()); } } // 优先使用Intent中的数据 if (rawMsgs != null && rawMsgs.length > 0) { msgs = new NdefMessage[rawMsgs.length]; for (int i = 0; i < rawMsgs.length; i++) { msgs[i] = (NdefMessage) rawMsgs[i]; } } buildTagViews(msgs); } } private void buildTagViews(NdefMessage[] msgs){ if (msgs != null && msgs.length > 0){ String text = ""; NdefRecord record = msgs[0].getRecords()[0]; byte[] payload = record.getPayload(); String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; int languageCodeLength = payload[0] & 0x3F; try { text = new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding); } catch (UnsupportedEncodingException e) { Log.e("UnsupportedEncoding", e.toString()); } Log.d("myTag", text); nfc_contents.setText("NFC内容: " + text); } else { nfc_contents.setText("该NFC标签无可用NDEF数据"); Log.d("myTag", "未找到NDEF消息"); } } private void write(String text, Tag tag) throws IOException, FormatException{ NdefRecord[] records = { createRecord(text) }; NdefMessage message = new NdefMessage(records); Ndef ndef = Ndef.get(tag); ndef.connect(); ndef.writeNdefMessage(message); ndef.close(); } private NdefRecord createRecord(String text) throws UnsupportedEncodingException { String lang = "en"; byte[] textBytes = text.getBytes(); 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); } @Override protected void onNewIntent(Intent intent){ super.onNewIntent(intent); setIntent(intent); readfromIntent(intent); if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())){ myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); } } @Override public void onPause(){ super.onPause(); WriteModeOff(); } @Override public void onResume(){ super.onResume(); WriteModeOn(); } private void WriteModeOn(){ writeMode = true; nfcAdapter.enableForegroundDispatch(this, pendingIntent, writingTagFilters, null); } private void WriteModeOff(){ writeMode = false; nfcAdapter.disableForegroundDispatch(this); } }
额外优化说明
- 添加
PendingIntent.FLAG_MUTABLE适配Android 12+系统权限要求 - 替换按钮点击事件为Lambda写法,简化代码结构
- 将提示文本改为中文,适配国内使用场景
内容的提问来源于stack exchange,提问作者Ufuk Sipor
相关产品推荐
相关产品推荐

