[英]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.