gpt4 book ai didi

java - 接收 NFC 的应用程序总是在前面弹出新实例

转载 作者:行者123 更新时间:2023-11-30 01:16:58 26 4
gpt4 key购买 nike

通过启动器启动我的应用程序时,我会经历以下生命周期:

onCreate..., onPostCreate...,  onResume..., onNewIntent..., act:android.intent.action.MAIN, mNfcAdapter.disableForegroundDispatch OK.

然后当我点击一个标签时,一个新的应用程序实例似乎在我运行以下生命周期时启动:

onPause..., onCreate..., onPostCreate...,  onResume..., onNewIntent..., act:android.nfc.action.TAG_DISCOVERED, myTag.mId:048a1382bd2384)

因为我尝试使用前台调度系统来禁用接收 NFC 事件,所以我希望我的应用程序忽略 NFC 标签。那么为什么要重新创建我的 Activity 呢?是因为AndroidManifest.xml允许吗?

package com.example.pdf.nfcaccess;

import android.annotation.SuppressLint;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;

// PDf import
import android.telephony.TelephonyManager;
import android.content.Intent;
import android.content.Context;
import android.content.IntentFilter;
import android.app.PendingIntent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcEvent;
import android.widget.TextView;
import android.widget.Toast;
import android.util.Log;
import android.nfc.tech.NfcF;
import android.nfc.Tag;

/**
* An example full-screen activity that shows and hides the system UI (i.e.
* status bar and navigation/system bar) with user interaction.
*/
public class FullscreenActivity extends AppCompatActivity {
/**
* Whether or not the system UI should be auto-hidden after
* {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
*/
private static final boolean AUTO_HIDE = true;

/**
* If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after
* user interaction before hiding the system UI.
*/
private static final int AUTO_HIDE_DELAY_MILLIS = 3000;

/**
* Some older devices needs a small delay between UI widget updates
* and a change of the status and navigation bar.
*/
private static final int UI_ANIMATION_DELAY = 300;
private final Handler mHideHandler = new Handler();
private View mContentView;
private final Runnable mHidePart2Runnable = new Runnable() {
@SuppressLint("InlinedApi")
@Override
public void run() {
// Delayed removal of status and navigation bar

// Note that some of these constants are new as of API 16 (Jelly Bean)
// and API 19 (KitKat). It is safe to use them, as they are inlined
// at compile-time and do nothing on earlier devices.
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
};
private View mControlsView;

// application
static FullscreenActivity mInstance;

NfcAdapter mNfcAdapter;
Intent mNfcIntent;
PendingIntent mNfcPendingIntent;
IntentFilter mTagIntentFilter;
IntentFilter[] mIntentFiltersArray;
String[][] mTechLists;
TextView mTagContentText;

// log
//java.util.ArrayList<String> mLogItems = new java.util.ArrayList<String>();
java.util.ArrayList<String> mLogItems = new java.util.ArrayList<String>();
android.widget.ArrayAdapter<String> mLogAdapter;
android.widget.ListView mLogList;

/**/
private final Runnable mShowPart2Runnable = new Runnable() {
@Override
public void run() {
// Delayed display of UI elements
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.show();
}
mControlsView.setVisibility(View.VISIBLE);
}
};
private boolean mVisible;
private final Runnable mHideRunnable = new Runnable() {
@Override
public void run() {
hide();
}
};
/**
* Touch listener to use for in-layout UI controls to delay hiding the
* system UI. This is to prevent the jarring behavior of controls going away
* while interacting with activity UI.
*/

/* Enable NFC
*/
private final View.OnTouchListener mFuncNfcEnable = new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
traceTry("mFuncNfcEnable");
if (mNfcAdapter != null) {
try {
traceTry("mNfcAdapter.enableForegroundDispatch");
mNfcAdapter.enableForegroundDispatch(FullscreenActivity.mInstance, mNfcPendingIntent, mIntentFiltersArray, mTechLists);
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
}
return false;
}
};

/* read Intent
*/
private final View.OnTouchListener mFuncNfcRead = new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (mNfcAdapter != null) {
try {
traceTry("onNewIntent");
onNewIntent(getIntent());
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
return false;
}
};

/* Disable NFC
*/
private final View.OnTouchListener mFuncNfcDisable = new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN){
traceTry("mFuncNfcDisable");
if (mNfcAdapter != null) {
try {
traceTry("mNfcAdapter.disableForegroundDispatch");
mNfcAdapter.disableForegroundDispatch(FullscreenActivity.mInstance);
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
}
return false;
}
};

/* Quit
*/
private final View.OnTouchListener mFuncBtnQuit = new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
finish();
return false;
}
};

/**/
private void trace(String m) {
Log.d("NFCTags",m);
/*TextView tv = (TextView)findViewById(R.id.logContent_value);
String previous = tv.getText().toString();
tv.setText(previous + "\n" + m);*/
if (mLogAdapter != null) {
mLogItems.add(m);
mLogAdapter.notifyDataSetChanged();
mLogList.setSelection(mLogList.getCount()-1);
}
}

String mMessage = "";
private void traceTry(String m) {
trace(m + "...");
mMessage = m;
}

private void traceOk() {
trace(mMessage + " OK");
mMessage = "";
}

private void traceFails(Throwable t) {
String msg = mMessage + " fails";
if (t != null) {
msg += " exception:" + t.getMessage();
}
trace(msg);
//Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
mMessage = "";
}

/*
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

trace("onCreate...");

// set global unique instance
FullscreenActivity.mInstance = this;

setContentView(R.layout.activity_fullscreen);

// log
mLogItems.add("starts");
mLogAdapter = new android.widget.ArrayAdapter<String>(this, R.layout.support_simple_spinner_dropdown_item, mLogItems);
mLogList = (android.widget.ListView) findViewById(R.id.logList_value);
mLogList.setAdapter(mLogAdapter);

mVisible = true;
mControlsView = findViewById(R.id.fullscreen_content_controls);
mContentView = findViewById(R.id.fullscreen_content);
mTagContentText = (TextView) findViewById(R.id.tagContent_value);

// Set up the user interaction to manually show or hide the system UI.
mContentView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
toggle();
}
});

// Upon interacting with UI controls, delay any scheduled hide()
// operations to prevent the jarring behavior of controls going away
// while interacting with the UI.

findViewById(R.id.nfcRead_btn).setOnTouchListener(mFuncNfcRead);

//findViewById(R.id.nfcDisable_btn).setOnTouchListener(mFuncNfcDisable);

findViewById(R.id.quit_btn).setOnTouchListener(mFuncBtnQuit);

trace("onCreate > before initializing nfc");

TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
trace("ID:" + tm.getDeviceId());
trace("Network Operator Name:" + tm.getNetworkOperatorName());
trace("Sim Operator Name:" + tm.getSimOperatorName());
trace("Sim Serial Number:" + tm.getSimSerialNumber());
trace("Phone Type:" + tm.getPhoneType());
trace("Initial Phone Number:" + tm.getLine1Number());

boolean tryNfc = true;

if (tryNfc) {

try {
mMessage = "NfcAdapter.getDefaultAdapter";
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (mNfcAdapter == null) {
mMessage = "NFC is not available";
traceFails(null);
return;
} else {
traceOk();
}
} catch (Throwable t) {
traceFails(t);
return;
}

// Check if NFC is enabled
try {
mMessage = "test NfcAdapter.isEnabled";
if (!mNfcAdapter.isEnabled()) {
mMessage = "NFC is not enabled. do it manually";
traceFails(null);
return;
} else {
trace("NFC is enabled.");
}
} catch (Throwable t) {
traceFails(t);
return;
}

try {
mMessage = "create new Intent";
mNfcIntent = new Intent(this, getClass());
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}

try {
mMessage = "mNfcIntent.addFlags, PendingIntent.getActivity";
mNfcIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
mNfcPendingIntent = PendingIntent.getActivity(this, 0, mNfcIntent, 0);
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}

try {
mMessage = "new IntentFilter";
mTagIntentFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
mTagIntentFilter.addCategory(Intent.CATEGORY_DEFAULT);
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}

try {
mMessage = "addDataType, new IntentFilter[]";
mTagIntentFilter.addDataType("*/*");
//mTagIntentFilter.addDataType("text/plain");
mIntentFiltersArray = new IntentFilter[]{mTagIntentFilter};
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}

// Setup a tech list for all NfcF tags
try {
mMessage = "new tech list";
//mTechLists = new String[][]{new String[]{NfcF.class.getName()}};
mTechLists = new String[][]{};
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}

/*
if (mNfcAdapter != null) {
try {
mMessage = "mNfcAdapter.enableForegroundDispatch";
mNfcAdapter.enableForegroundDispatch(FullscreenActivity.mInstance, mNfcPendingIntent, mIntentFiltersArray, mTechLists);
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
*/
}
}

@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);

trace("onPostCreate...");

// Trigger the initial hide() shortly after the activity has been
// created, to briefly hint to the user that UI controls
// are available.
//delayedHide(100);
}

private void toggle() {

trace("toggle...");

if (mVisible) {
hide();
} else {
show();
}
}

private void hide() {

trace("hide...");

// Hide UI first
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.hide();
}
mControlsView.setVisibility(View.GONE);
mVisible = false;

// Schedule a runnable to remove the status and navigation bar after a delay
mHideHandler.removeCallbacks(mShowPart2Runnable);
mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
}

@SuppressLint("InlinedApi")
private void show() {
// Show the system bar
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
mVisible = true;

// Schedule a runnable to display UI elements after a delay
mHideHandler.removeCallbacks(mHidePart2Runnable);
mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
}

/**
* Schedules a call to hide() in [delay] milliseconds, canceling any
* previously scheduled calls.
*/
private void delayedHide(int delayMillis) {
mHideHandler.removeCallbacks(mHideRunnable);
mHideHandler.postDelayed(mHideRunnable, delayMillis);
}

/**/
public String intentToText(Intent intent){

String report = "?";
try {
Bundle bundle = intent.getExtras();
if (bundle != null) {
java.util.Set<String> keys = bundle.keySet();
java.util.Iterator<String> it = keys.iterator();
report = "Intent:{";
while (it.hasNext()) {
String key = it.next();
report += "\n[" + key + ":" + bundle.get(key) + "],";
}
report += "}\n";
}
}
catch(Throwable t){
trace("intentToText > " + t.getMessage());
}
return report;
}

/**/
public static String byteArrayToHex(byte[] a) {
StringBuilder sb = new StringBuilder(a.length * 2);
for(byte b: a)
sb.append(String.format("%02x", b & 0xff));
return sb.toString();
}

/**/
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);

trace("onNewIntent...");

handleIntent(intent);
}

/**/
void handleIntent(Intent intent) {

if (intent == null) return;

String sAction = intent.getAction();
trace("act:" + sAction);

if( (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()))
|| (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction()))
|| (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction()))) {

String payload = intent.getDataString();

mTagContentText.setText("act:" + sAction + "\n" + "pload:" + payload + "\n" + intentToText(intent));

Tag myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (myTag != null) {
trace("myTag.mId:" + byteArrayToHex(myTag.getId()));
mTagContentText.setText(mTagContentText.getText() + "\n" + "myTag.mId:" + byteArrayToHex(myTag.getId()));

android.os.Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMsgs != null) {
for (android.os.Parcelable p : rawMsgs) {
NdefMessage msg = (NdefMessage) p;
NdefRecord[] records = msg.getRecords();
for (NdefRecord record : records) {
short tnf = record.getTnf();
byte[] id = record.getId();
byte[] payLoad = record.getPayload();
}
}
}
}
}

}

/**/
@Override
protected void onResume() {
super.onResume();

trace("onResume...");
if (mNfcAdapter != null) {
try {
// See if the Activity is being started/resumed due to an NFC event and handle it
onNewIntent( getIntent());
}
catch (Throwable t) {
traceFails(t);
}

try {
mMessage = "mNfcAdapter.disableForegroundDispatch";
mNfcAdapter.disableForegroundDispatch(FullscreenActivity.mInstance);
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
}

/**/
@Override
protected void onPause() {
super.onPause();

trace("onPause...");
}
}

AndroidManifest.xml 是:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.pdf.nfcaccess">

<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>

<application
android:allowBackup="true"
android:icon="@mipmap/ic_pdflauncher"
android:label="@string/app_name"
android:supportsRtl="true"
android:debuggable="true"
android:theme="@style/AppTheme">
<activity
android:name=".FullscreenActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/app_name"
android:theme="@style/FullscreenTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>

<!--intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain"/>
</intent-filter-->

</manifest>

最佳答案

您收到 NFC Intent (操作 TAG_DISCOVERED),因为您在 list 中注册了它:

<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

这也是您的 Activity 在收到 Intent 后重新创建的原因。

您为前台调度注册的 Intent 过滤器(具有任何 MIME 类型的操作 NDEF_DISCOVERED)似乎与您的标签不匹配(或者您尚未调用启用前台调度的代码段)。

请注意,调用 disableForegroundDispatch() 只会禁用先前通过 enableForegroundDispatch() 注册的前台调度。它不会影响 list 中的 Intent 过滤器。请参阅 Android: Can I enable/disable an activity's intent filter programmatically?,了解如何有选择地禁用在 list 中注册的 Intent 过滤器。但是,关于 NFC Intent ,您可能希望通过前台调度系统注册接收 所有 标签的事件,然后在收到 onNewIntent() 中的事件后有选择地忽略您不想要的标签.

关于您的代码的更多信息(实际上只是关于 NFC 部分)

  1. 对于 list 中的 NDEF_DISCOVERED Intent 过滤器,您通常还希望指定一个与标签数据类型匹配的 <data ... /> 元素。

  2. 不要在您的 list 中使用 TAG_DISCOVERED Intent 过滤器(除非您真的理解并想要它的影响)。 TAG_DISCOVERED Intent 过滤器(在 list 中使用时)只是 API 级别 9(Android 2.3.3 之前)的兼容模式,其中 NFC 支持非常非常有限,并且是一种后备模式,可以用于创建处理 任何其他 应用程序不支持的 NFC 标签的应用程序。

  3. TECH_DISCOVERED Intent 过滤器需要技术列表 XML 文件以匹配任何标签。因此, list 中此过滤器的当前版本永远不会匹配任何内容。

  4. disableForegroundDispatch() 中调用 onResume() 没有任何意义。按照设计,在 Activity 生命周期的此时永远无法启用前台调度。原因是不能在enableForegroundDispatch()之前调用onResume(),要求最迟在disableForegroundDispatch()调用onPause()

  5. 事实上,在 enableForegroundDispatch()/disableForegroundDispatch() 以外的任何地方使用 onResume()/onPause() 是没有意义的。如果你想停止监听其他事件的标签(例如按下按钮),你只需记住一些标志中的当前状态(处理/不处理 NFC 事件),当你在 onNewIntent() 中收到新的 NFC Intent 时,您将处理或静默忽略基于该标志的标签。

  6. 您的代码不应手动调用 Activity 生命周期方法(正如您当前使用 onNewIntent(getIntent()); 所做的那样)。

关于java - 接收 NFC 的应用程序总是在前面弹出新实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37702519/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com