从标签获取NDEF消息冻结Android应用 [英] Getting NDEF message from tag freezes Android app
问题描述
我想从一个NFC标签读取NDEF消息。标签的检测工作正常。对于从标签读取的数据NDEF我跑一个TimerTask。任务民调来自标签的NDEF消息, getNdefMessage()
每900毫秒,并更新用户界面。
程序完美的作品,直到我取出手机。比应用程序冻结没有logcat的错误消息。
有没有人有一个想法,为什么出现这种情况?
包com.example.infcdemo;进口java.io.IOException异常;
进口java.util.Timer中;进口android.app.Activity;
进口android.app.PendingIntent;
进口android.content.Intent;
进口android.content.IntentFilter;
进口android.nfc.NfcAdapter;
进口android.nfc.Tag;
进口android.nfc.tech.Ndef;
进口android.nfc.tech.NdefFormatable;
进口android.nfc.tech.NfcA;
进口android.os.Bundle;
进口android.os.Handler;
进口android.widget.TextView;公共类MainActivity扩展活动
{
保护NfcAdapter mAdapter;
受保护的PendingIntent mPendingIntent;
受保护的IntentFilter mIntentfilter;
保护的String [] [] mTechLists;
受保护的IntentFilter [] mFilters;
保护NFCA NFCA = NULL;
保护意图mIntent = NULL;
保护特征MTAG;
私人布尔nfc_initialized = FALSE; 标签MyTag的= NULL;
NDEF _ndef = NULL; 定时器_incomingMessageTimer;
@覆盖
保护无效的onCreate(捆绑savedInstanceState)
{
super.onCreate(savedInstanceState);
的setContentView(R.layout.activity_main); 如果(nfc_initialized == FALSE)
{
//初始化NFC具体
mAdapter = NfcAdapter.getDefaultAdapter(本);
mPendingIntent = PendingIntent.getActivity(这一点,0,
新的意图(这一点,的getClass())
.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),1);
IntentFilter的NDEF =新的IntentFilter(
NfcAdapter.ACTION_TAG_DISCOVERED);
mTechLists =新的String [] [] {新的String [] {NfcA.class.getName(),Ndef.class.getName()
NdefFormatable.class.getName()}};
mFilters =新的IntentFilter [] {NDEF,};
nfc_initialized = TRUE;
}
} 公共无效updateIncomingMessage(弦乐味精)
{
TextView的txtView =(的TextView)findViewById(R.id.txtReceive);
txtView.setText(MSG);
} @覆盖
保护无效调用onStart()
{
super.onStart(); _incomingMessageTimer =新的Timer();
_incomingMessageTimer.schedule(新MessageReceiveTimer(新的处理程序(),这一点),0900);
} @覆盖
保护无效的onStop()
{
super.onStop(); _incomingMessageTimer.cancel();
_incomingMessageTimer.purge(); } @覆盖
公共无效onNewIntent(意向意图)
{
mIntent =意图; 字符串行动= intent.getAction();
如果(NfcAdapter.ACTION_TAG_DISCOVERED.equals(动作))
{
MyTag的= intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 如果(_ndef!= NULL)
{
尝试
{
_ndef.close();
_ndef = NULL;
}
赶上(IOException异常E)
{
e.printStackTrace();
}
} 如果(_ndef == NULL)
{
_ndef = Ndef.get(MyTag的); 尝试
{
_ndef.connect();
}
赶上(IOException异常E)
{
e.printStackTrace();
}
}
}
}
@覆盖
公共无效的onPause()
{
super.onPause();
mAdapter.disableForegroundDispatch(本);
} @覆盖
公共无效onResume()
{
super.onResume();
mAdapter.enableForegroundDispatch(这一点,mPendingIntent,mFilters,
mTechLists);
}
}
// TimerTask的类
包com.example.infcdemo;
进口java.util.TimerTask中;进口android.nfc.NdefMessage;
进口android.os.Handler;公共类MessageReceiveTimer扩展的TimerTask
{
处理器_handler;
MainActivity _mainActivity; MessageReceiveTimer(处理程序处理程序,MainActivity mainActivity)
{
超();
_handler =处理程序;
_mainActivity = mainActivity;
} @覆盖
公共无效的run()
{
_handler.post(新的Runnable()
{
@覆盖
公共无效的run()
{
尝试
{
如果(_mainActivity._ndef!= NULL)
{
NdefMessage ndefMsg = NULL; 如果(_mainActivity._ndef.isConnected())
ndefMsg = _mainActivity._ndef.getNdefMessage();
其他
ndefMsg = NULL; 字节[] = ndefRecord ndefMsg.getRecords()[0] .getPayload();
字符串strMsg =新的String(ndefRecord,US-ASCII);
_mainActivity.updateIncomingMessage(strMsg);
}
}
赶上(例外五)
{
返回;
}
}
});
}
}
您的应用程序块,当你删除一个标签的原因是,你在你的应用程序的主线程(UI线程)标签执行IO操作。
您首先创建一个处理其预定任务的计时器的独立的主题
_incomingMessageTimer =新的Timer();
^^^^^^^^^^^
_incomingMessageTimer.schedule(新MessageReceiveTimer(新处理程序(),这一点),0,900);
^^^^^^^^
然而,当TimerTask的执行(定时器螺纹上)
公共类MessageReceiveTimer扩展的TimerTask {
@覆盖
公共无效的run(){
// code excecution发生在计时器线程
}
}
您立即发布一个Runnable上的邮件队列控制权返回给主(UI)线程:
_handler.post(新的Runnable(){
@覆盖
公共无效的run(){
// code执行发生在处理器的线程
}
});
处理程序的线程是在你的情况下,主(UI)线程为您创建的主线程处理程序:
_incomingMessageTimer.schedule(新MessageReceiveTimer(新的处理程序(),这一点),0900);
^^^^^^^^^^^^^
因此IO操作( _mainActivity._ndef.getNdefMessage()
)将阻止主线程。需要注意的是Android文档明确地说,这种方法的不得从主应用程序线程名为的(见的这里)。这同样适用于 连接()
方法,顺便说一句。
I'm trying to read an NDEF message from an NFC tag. The detection of the tag works correctly. For reading the NDEF data from the tag I'm running a TimerTask. The task polls the NDEF message from the tag with getNdefMessage()
every 900 ms and updates the UI.
The procedure works perfect until I remove the phone. Than the app freezes without a logcat error message.
Does anyone have an idea why this happens?
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 Class
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;
}
}
});
}
}
The reason your app blocks when you remove a tag is that you execute IO operations on the tag in your app's main thread (UI thread).
You first create a timer that processes its scheduled tasks in a separate thread
_incomingMessageTimer = new Timer();
^^^^^^^^^^^
_incomingMessageTimer.schedule(new MessageReceiveTimer(new Handler(), this), 0, 900);
^^^^^^^^
However, when the TimerTask executes (on the Timer thread)
public class MessageReceiveTimer extends TimerTask {
@Override
public void run() {
// code excecution happens in the Timer thread
}
}
you immediately return control to the main (UI) thread by posting a Runnable on its message queue:
_handler.post(new Runnable() {
@Override
public void run() {
// code execution happens in the Handler's thread
}
});
The Handler's thread is the main (UI) thread in your case as you created the handler on the main thread:
_incomingMessageTimer.schedule(new MessageReceiveTimer(new Handler(), this),0,900);
^^^^^^^^^^^^^
Consequently the IO operation (_mainActivity._ndef.getNdefMessage()
) will block the main thread. Note that the Android documentation explicitly says that this method "must not be called from the main application thread" (see here). The same applies to the connect()
method, btw.
这篇关于从标签获取NDEF消息冻结Android应用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!