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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 03:07:36