我试图从NFC标签上读取NDEF消息。标签的检测正常工作。用于从标签I中读取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;
}
}
});
}
}
答案 0 :(得分:1)
删除标记时应用程序阻止的原因是您在应用程序的主线程(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
}
});
当您在主线程上创建处理程序时,Handler的线程是您的主要(UI)线程:
_incomingMessageTimer.schedule(new MessageReceiveTimer(new Handler(), this),0,900);
^^^^^^^^^^^^^
因此IO操作(_mainActivity._ndef.getNdefMessage()
)将阻塞主线程。请注意,Android文档明确指出此方法“不得从主应用程序线程”调用(请参阅here)。这同样适用于connect()
method,顺便说一句。