簡體   English   中英

從標簽獲取NDEF消息會凍結Android應用

[英]Getting NDEF message from tag freezes Android app

我正在嘗試從NFC標簽讀取NDEF消息。 標簽的檢測正常進行。 為了從標簽讀取NDEF數據,我正在運行TimerTask。 該任務每900毫秒使用getNdefMessage()從標簽輪詢NDEF消息,並更新UI。

在我取下手機之前,該程序可以正常運行。 比應用程序凍結時沒有出現logcat錯誤消息。

有誰知道為什么會這樣?

package com.example.infcdemo;

import java.io.IOException;
import java.util.Timer;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.nfc.tech.NdefFormatable;
import android.nfc.tech.NfcA;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;

public class MainActivity extends Activity
{
    protected NfcAdapter mAdapter;
    protected PendingIntent mPendingIntent;
    protected IntentFilter mIntentfilter;
    protected String[][] mTechLists;
    protected IntentFilter[] mFilters;
    protected NfcA nfca = null;
    protected Intent mIntent = null;
    protected Tag mTag;
    private boolean nfc_initialized = false;

    Tag myTag = null;
    Ndef _ndef = null;

    Timer _incomingMessageTimer;


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

        if (nfc_initialized == false) 
        {
            // Initialize NFC Specific
            mAdapter = NfcAdapter.getDefaultAdapter(this);
            mPendingIntent = PendingIntent.getActivity(this, 0,
                    new Intent(this, getClass())
                            .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 1);
            IntentFilter ndef = new IntentFilter(
                    NfcAdapter.ACTION_TAG_DISCOVERED);
            mTechLists = new String[][] { new String[] { NfcA.class.getName(), Ndef.class.getName(),
                    NdefFormatable.class.getName() } };
            mFilters = new IntentFilter[] { ndef, };
            nfc_initialized = true;
        }
    }

    public void updateIncomingMessage(String msg)
    {
        TextView txtView = (TextView) findViewById(R.id.txtReceive);
        txtView.setText(msg);
    }

    @Override
    protected void onStart()
    {
        super.onStart();

        _incomingMessageTimer = new Timer();
        _incomingMessageTimer.schedule(new MessageReceiveTimer(new Handler(), this),0,900);
    }

    @Override
    protected void onStop()
    {
        super.onStop();

        _incomingMessageTimer.cancel();
        _incomingMessageTimer.purge();

    }

    @Override
    public void onNewIntent(Intent intent) 
    {
        mIntent = intent;

        String action = intent.getAction();
        if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) 
        {
            myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

            if(_ndef != null)
            {
                try 
                {
                    _ndef.close();
                    _ndef = null;
                } 
                catch (IOException e) 
                {
                    e.printStackTrace();
                }
            }

            if(_ndef == null)
            {
                _ndef = Ndef.get(myTag);

                try 
                {
                    _ndef.connect();
                } 
                catch (IOException e) 
                {
                    e.printStackTrace();
                }
            }
        } 
    }
    @Override
    public void onPause()
    {
        super.onPause();
        mAdapter.disableForegroundDispatch(this);
    }

    @Override
    public void onResume() 
    {
        super.onResume();
        mAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters,
            mTechLists);
    }
}

// TimerTask類

package com.example.infcdemo;
import java.util.TimerTask;

import android.nfc.NdefMessage;
import android.os.Handler;

public class MessageReceiveTimer extends TimerTask
{
    Handler _handler;
    MainActivity _mainActivity;

    MessageReceiveTimer(Handler handler, MainActivity mainActivity)
    {
        super();
        _handler = handler;
        _mainActivity = mainActivity;
    }

    @Override
    public void run() 
    {
        _handler.post(new Runnable() 
        {
            @Override
            public void run() 
            {
                try 
                {
                    if(_mainActivity._ndef != null)
                    {
                        NdefMessage ndefMsg = null;

                        if(_mainActivity._ndef.isConnected())
                            ndefMsg = _mainActivity._ndef.getNdefMessage();
                        else
                            ndefMsg = null;

                        byte[] ndefRecord = ndefMsg.getRecords()[0].getPayload();
                        String strMsg = new String(ndefRecord, "US-ASCII"); 
                        _mainActivity.updateIncomingMessage(strMsg);
                    }
                } 
                catch (Exception e)
                {
                    return;
                }
            }
        });
    }
}

刪除標簽時,您的應用程序阻塞的原因是您對應用程序的主線程(UI線程)中的標簽執行了IO操作。

您首先創建一個計時器,以在單獨的線程中處理其計划的任務

_incomingMessageTimer = new Timer();
                        ^^^^^^^^^^^
_incomingMessageTimer.schedule(new MessageReceiveTimer(new Handler(), this), 0, 900);
                      ^^^^^^^^

但是,當TimerTask執行時(在Timer線程上)

public class MessageReceiveTimer extends TimerTask {
    @Override
    public void run() {
        // code excecution happens in the Timer thread
    }
}

您可以通過在其消息隊列上發布Runnable立即將控制權返回給主(UI)線程:

_handler.post(new Runnable() {
    @Override
    public void run() {
        // code execution happens in the Handler's thread
    }
});

在您的情況下,在主線程上創建處理程序時,處理程序的線程是主(UI)線程:

_incomingMessageTimer.schedule(new MessageReceiveTimer(new Handler(), this),0,900);
                                                       ^^^^^^^^^^^^^

因此,IO操作( _mainActivity._ndef.getNdefMessage() )將阻塞主線程。 請注意,Android文檔明確指出此方法“ 不得從主應用程序線程中調用 ”(請參見此處 )。 btw的connect()方法也是如此

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM