[英]how to intercept NFC tag before onNewIntent executes
我有一個捕獲NFC標簽的應用程序。 我過去遇到的問題是,用戶以不穩定的方式懸停在標簽上,導致NFC適配器觸發兩次。
我已經做了幾件事來應對這個問題。
表現:
<activity
android:name=".NfcActivity"
android:screenOrientation="portrait"
android:launchMode="singleTask"
android:noHistory="true"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
這會將NFC捕獲活動設置為堆棧中的唯一實例,並且沒有歷史記錄。 我已經覆蓋了所有可以停止並重新啟動此活動的配置更改,后者可能導致將意圖數據重新傳遞到該活動,使其看起來像重復掃描。
在活動本身中,我已覆蓋onNewIntent,但只顯示了錯誤的掃描屏幕,什么也沒做。 從功能的角度來看,我還理解onNewIntent應該反映onCreate,但是由於該應用程序的先前版本已將2次掃描發送到下一個Activity,因此我只希望NFC在一個地方捕獲代碼onCreate。
在onCreate中,我進行了進一步的測試,以防止將鼠標懸停在標簽上並創建錯誤的掃描。
該應用程序似乎可以正常運行,但可以在一部特定的手機(三星Galaxy Young 2)上使用,如果用戶將手機放在標簽上幾秒鍾,則NFC適配器似乎連續觸發了幾次。
發生這種情況時,原始掃描將被取消。 這樣做的原因是oncreate處理標簽,但是在隨后的掃描發生時(由於懸停,偶然發生),將運行onPause-> onNewIntent。 因此,活動從onCreate跳出並停止處理標記。 onNewIntent顯示失敗的掃描屏幕並啟動菜單屏幕。
上面的問題不大,因為發生的一切是用戶必須重新掃描標簽。
我想發生的是:
當onCreate運行時,即使執行onNewintent,也無論如何處理標記。 有沒有辦法在到達onNewintent和onPause之前攔截意圖?
也許有一個我可以使用的全局標志,可以首先檢查該標志以表明onCreate仍在運行,而onNewIntent不應該運行,或更重要的是,不叫onPause不使onCreate停止運行。
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.ndeftools.Message;
import org.ndeftools.Record;
import android.app.Activity;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.os.Vibrator;
import android.util.Log;
import android.widget.Toast;
public class NfcActivity extends Activity {
private static final String TAG = NfcActivity.class.getName();
protected NfcAdapter nfcAdapter;
protected PendingIntent nfcPendingIntent;
Handler handler;
Runnable runnable;
Handler failHandler;
Runnable failRunnable;
Parcelable[] messages;
Intent i;
Tag tag;
String tagId;
boolean nfcConnected;
ProgressDialog progressDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.nfcactivitylayout);
Log.e(TAG, "oncreate");
nfcConnected = false;
// initialize NFC
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, this.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
tag = null;
tagId = null;
i = getIntent();
if ((i.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
//check to see if Android has previously killed the app and relaunched it from History
//and delivered the original intent.
//if it has do not process and launch the menu screen
Intent processPayloadIntent = new Intent(NfcActivity.this, NfcscannerActivity.class);
processPayloadIntent.setAction("QRCODE_ACTION");
processPayloadIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(processPayloadIntent);
}else{
tag = i.getParcelableExtra(NfcAdapter.EXTRA_TAG);
tagId = bytesToHexString(tag.getId());
Log.e(TAG, "tagID = " + tagId);
Log.e(TAG, "oncreate intent action = " + i.getAction());
//The activity has captured tag data, prove the user is not hovering over the tag and is doing a good scan
//hovering can trigger the adapter twice
AsyncNfcConnect asnc = new AsyncNfcConnect();
try {
asnc.execute().get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e(TAG, "nfcConnected!!!!!!!!!!!!!!!!!!!!!!!!! = " + nfcConnected);
if(nfcConnected == true){
int buildVersionSdk = Build.VERSION.SDK_INT;
int buildVersionCodes = Build.VERSION_CODES.GINGERBREAD;
Log.e(TAG, "buildVersionSdk = " + buildVersionSdk
+ "buildVersionCodes = " + buildVersionCodes);
int themeVersion;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD) {
themeVersion = 2;
} else {
themeVersion = 1;
}
try{
progressDialog = new ProgressDialog(this, themeVersion);
progressDialog.setTitle("NFC Tag Scanned");
progressDialog.setMessage("Processing tag...");
progressDialog.setIndeterminate(true);
progressDialog.show();
}catch(Exception e){ }
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(i.getAction()) || NfcAdapter.ACTION_TAG_DISCOVERED.equals(i.getAction())) {
if(NfcScannerApplication.isCanScanNfcTag()){
messages = i.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (messages != null) {
//setContentView(R.layout.successfulnfc);
NfcScannerApplication.startNfcTimer();
//Toast.makeText(this, "NFC timer set", Toast.LENGTH_LONG).show();
Log.e(TAG, "Found " + messages.length + " NDEF messages"); // is almost always just one
vibrate(); // signal found messages :-)
initHandler();
handler.postDelayed(runnable, 2000);
}else{
Toast.makeText(this, "Data on tag was not correct", Toast.LENGTH_LONG).show();
try{
handler.removeCallbacks(runnable);
Log.e(TAG, "just removed callback to runnable that reads nfc tag data");
}catch(Exception e){
}
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
}else{
try{
handler.removeCallbacks(runnable);
Log.e(TAG, "just removed callback to runnable that reads nfc tag data");
}catch(Exception e){
}
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
} else {
Toast.makeText(this, "Tag not recognized correctly", Toast.LENGTH_LONG).show();
try{
handler.removeCallbacks(runnable);
Log.e(TAG, "just removed callback to runnable that reads nfc tag data");
}catch(Exception e){
}
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
}else{
try{
Toast.makeText(this, "Phone wasn't connected to Tag", Toast.LENGTH_LONG).show();
handler.removeCallbacks(runnable);
Log.e(TAG, "just removed callback to runnable that reads nfc tag data");
}catch(Exception e){
}
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}//end of NFC connect test
}//end of launched from history check
}//end of onCreate
@Override
protected void onStart() {
super.onStart();
Log.e(TAG, "onStart");
}
@Override
protected void onStop() {
super.onStop();
Log.e(TAG, "onStop");
}
@Override
public void onNewIntent(Intent intent) {
Log.e(TAG, "onNewIntent");
Toast.makeText(this, "Bad scan!!!", Toast.LENGTH_LONG).show();
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}//end of onNewIntent
public void enableForegroundMode() {
Log.e(TAG, "enableForegroundMode");
IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED); // filter for all
IntentFilter[] writeTagFilters = new IntentFilter[] {tagDetected};
nfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null);
}
public void disableForegroundMode() {
Log.e(TAG, "disableForegroundMode");
nfcAdapter.disableForegroundDispatch(this);
}
@Override
protected void onResume() {
super.onResume();
Log.e(TAG, "onResume");
enableForegroundMode();
}
@Override
protected void onPause() {
Log.e(TAG, "onPause");
super.onPause();
disableForegroundMode();
if(handler != null){
handler.removeCallbacks(runnable);
}
}
private void vibrate() {
Log.e(TAG, "vibrate");
Vibrator vibe = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE) ;
vibe.vibrate(500);
}
public void initHandler(){
handler = new Handler();
runnable = new Runnable() {
public void run() {
processTag();
}
private void processTag() {
Log.e(TAG, "about to process tag");
try{
progressDialog.dismiss();
}catch(Exception e){
//do nothing
}
// parse to records
for (int i = 0; i < messages.length; i++) {
try {
List<Record> records = new Message((NdefMessage)messages[i]);
Log.e(TAG, "Found " + records.size() + " records in message " + i);
for(int k = 0; k < records.size(); k++) {
Log.e(TAG, " Record #" + k + " is of class " + records.get(k).getClass().getSimpleName());
Record record = records.get(k);
NdefRecord ndefRecord = record.getNdefRecord();
byte[] arr = ndefRecord.getPayload();
String payload = new String(arr);
if(payload.length() > 0){
payload = payload.substring(3, payload.length());
Log.e(TAG, "payload = " + payload);
String[] splitPayload = payload.split(",");
String tagType = splitPayload[0];
String tagCompany = splitPayload[1];
String tagClientID = splitPayload[2];
String tagClientName = splitPayload[3];
if(! tagClientID.equalsIgnoreCase("0") && tagClientID.length() > 0){
handler.post(new Runnable(){
public void run() {
setContentView(R.layout.successfulnfc);
}
});
Intent processPayloadIntent = new Intent(NfcActivity.this, NfcscannerActivity.class);
processPayloadIntent.putExtra("payload", payload);
processPayloadIntent.putExtra("tagid", tagId);
processPayloadIntent.setAction("NFC");
processPayloadIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//processPayloadIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(processPayloadIntent);
finish();
overridePendingTransition(0, R.anim.activity_animation_zoom_in);
}else{
Toast.makeText(NfcActivity.this, "Tag data problem/Scan problem.", Toast.LENGTH_LONG).show();
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
}else{
Toast.makeText(NfcActivity.this, "Tag data problem/Scan problem.", Toast.LENGTH_LONG).show();
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
}
} catch (Exception e) {
Log.e(TAG, "Problem parsing message", e);
}
}
}
};
}
public void initFailHandler(){
failHandler = new Handler();
failRunnable = new Runnable() {
public void run() {
returnToMainMenu();
}
private void returnToMainMenu() {
//Log.e(TAG, "about to return to main menu");
try{
progressDialog.dismiss();
}catch(Exception e){
//do nothing
}
Toast.makeText(NfcActivity.this, "Please check your scanning technique.\nPlease do not hover over tag or swipe...", Toast.LENGTH_LONG).show();
failHandler.post(new Runnable(){
public void run() {
setContentView(R.layout.nfcfail);
}
});
//onBackPressed();
Intent processPayloadIntent = new Intent(NfcActivity.this, NfcscannerActivity.class);
processPayloadIntent.setAction("QRCODE_ACTION");
processPayloadIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(processPayloadIntent);
finish();
//overridePendingTransition(0, R.anim.activity_animation_zoom_in);
}
};
}
private String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("0x");
if (src == null || src.length <= 0) {
return null;
}
char[] buffer = new char[2];
for (int i = 0; i < src.length; i++) {
buffer[0] = Character.forDigit((src[i] >>> 4) & 0x0F, 16);
buffer[1] = Character.forDigit(src[i] & 0x0F, 16);
System.out.println(buffer);
stringBuilder.append(buffer);
}
return stringBuilder.toString();
}
private class AsyncNfcConnect extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
NfcActivity.this.nfcConnected = false;
String result;
Ndef ndefTag = Ndef.get(tag);
try {
Log.e(TAG, "about to test connect()********************************************");
ndefTag.connect(); // this should already perform an IO operation and should therefore fail if there is no tag
Log.e(TAG, "Ndef.connect() connected!********************************************");
NdefMessage ndefMsg = ndefTag.getNdefMessage(); // this reads the current NDEF message from the tag and consequently causes an IO operation
NfcActivity.this.nfcConnected = true;
result = "OK";
return result;
} catch (Exception e) {
// there is no tag or communication with tag dropped
Log.e(TAG, "There a problem with connecting to the tag using Ndef.connect(");
NfcActivity.this.nfcConnected = false;
result = "NOTOK";
return result;
} finally {
try {
ndefTag.close();
} catch (Exception e) {
}
}
}
}//end of Async
}
您似乎堅持不處理onNewIntent()
NFC意圖。 我建議onCreate()
和onNewIntent()
都調用掃描標簽的通用過程。 這樣,兩個入口點將遵循相同的代碼路徑。
您聲稱應用程序“跳出onCreate”可能只是一種表達方式? 發生的情況是,標簽掃描AsyncNfcConnect
作為后台任務在單獨的線程上運行(應如此)。 該任務在onCreate()
創建,並在onCreate()
完成后繼續運行(您可以在onCreate()
的末尾添加一個Log
語句以進行檢查)。 正如您所觀察到的,當與標簽的連接以某種方式丟失並重新發現了標簽時,將調用onNewIntent()
。
無論如何,都無法阻止這種情況的發生,因此您的應用必須能夠處理它。 要檢測並處理它,您可以在活動中設置一些標志,以指示您的后台任務正在運行或已經運行。 您還可以存儲是否發生異常的信息,並在重新發現標簽后嘗試再次掃描標簽(這可能需要您實施我在上文中提出的建議)。 如果要使您的應用程序更能防止故障,還可以存儲上次掃描的標簽的ID,以便在成功掃描(或不成功)后重新發現該標簽時再次對其進行肯定標識。 當同一標簽持續發生異常時,您可以在一定次數后向用戶指示他的用戶(例如,通過建議該設備在標簽上放置不同的位置)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.