我有一个应用程序似乎工作正常并且可以很好地通过 NFC 传输数据。我有一个主要 Activity 、一个传输数据的 Activity 和一个接收数据的不同 Activity 。
发送方 Activity 运行良好,但当接收方收到 NFC Intent 时,它会将应用重新启动回到主 Activity。
我不太确定这是为什么。我希望它拒绝任何推送,除非用户已经在该 Activity 中,如果用户已经在该 Activity 中,则留在该 Activity 中并处理 NFC Intent 。
这是 list :
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Timer" />
<activity android:name=".AddSlaves"
android:label="Add Slave Devices"
android:launchMode="singleTask">
<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>
<activity android:name=".JoinSrv"
android:launchMode="singleTask">
<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>
这是发件人类:
public class JoinSrv extends Activity implements NfcAdapter.OnNdefPushCompleteCallback, NfcAdapter.CreateNdefMessageCallback {
//The array lists to hold our messages
private ArrayList<String> messagesToSendArray = new ArrayList<>();
private ArrayList<String> messagesReceivedArray = new ArrayList<>();
//Text boxes to add and display our messages
private NfcAdapter mNfcAdapter;
//Save our Array Lists of Messages for if the user navigates away
@Override
public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putStringArrayList("messagesToSend", messagesToSendArray);
savedInstanceState.putStringArrayList("lastMessagesReceived", messagesReceivedArray);
}
//Load our Array Lists of Messages for when the user navigates back
@Override
public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
messagesToSendArray = savedInstanceState.getStringArrayList("messagesToSend");
messagesReceivedArray = savedInstanceState.getStringArrayList("lastMessagesReceived");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_join_srv);
//Check if NFC is available on device
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (mNfcAdapter != null) {
//Handle some NFC initialization here
} else {
Toast.makeText(this, "NFC not available on this device",
Toast.LENGTH_SHORT).show();
}
//Check if NFC is available on device
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (mNfcAdapter != null) {
//This will refer back to createNdefMessage for what it will send
mNfcAdapter.setNdefPushMessageCallback(this, this);
//This will be called if the message is sent successfully
mNfcAdapter.setOnNdefPushCompleteCallback(this, this);
}
}
@Override
public NdefMessage createNdefMessage(NfcEvent event) {
//This will be called when another NFC capable device is detected.
//We'll write the createRecords() method in just a moment
NdefRecord[] recordsToAttach = createRecords();
//When creating an NdefMessage we need to provide an NdefRecord[]
return new NdefMessage(recordsToAttach);
}
@Override
public void onNdefPushComplete(NfcEvent event) {
//This is called when the system detects that our NdefMessage was
//Successfully sent.
messagesToSendArray.clear();
}
public NdefRecord[] createRecords() {
NdefRecord[] records = new NdefRecord[1];
//To Create Messages Manually if API is less than
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
byte[] payload = "192.168.1.100".
getBytes(Charset.forName("UTF-8"));
NdefRecord record = new NdefRecord(
NdefRecord.TNF_WELL_KNOWN, //Our 3-bit Type name format
NdefRecord.RTD_TEXT, //Description of our payload
new byte[0], //The optional id for our Record
payload); //Our payload for the Record
records[1] = record;
}
//Api is high enough that we can use createMime, which is preferred.
else {
byte[] payload = "192.168.1.100".
getBytes(Charset.forName("UTF-8"));
NdefRecord record = NdefRecord.createMime("text/plain",payload);
records[1] = record;
}
records[messagesToSendArray.size()] =
NdefRecord.createApplicationRecord(getPackageName());
return records;
}
private void handleNfcIntent(Intent NfcIntent) {
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(NfcIntent.getAction())) {
Parcelable[] receivedArray =
NfcIntent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (receivedArray != null) {
messagesReceivedArray.clear();
NdefMessage receivedMessage = (NdefMessage) receivedArray[0];
NdefRecord[] attachedRecords = receivedMessage.getRecords();
for (NdefRecord record : attachedRecords) {
String string = new String(record.getPayload());
//Make sure we don't pass along our AAR (Android Application Record)
if (string.equals(getPackageName())) {
continue;
}
messagesReceivedArray.add(string);
}
Toast.makeText(this, "Received " + messagesReceivedArray.size() +
" Messages", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Received Blank Parcel", Toast.LENGTH_LONG).show();
}
}
}
@Override
public void onNewIntent(Intent intent) {
handleNfcIntent(intent);
}
@Override
public void onResume() {
super.onResume();
handleNfcIntent(getIntent());
}
}
这是接收类:
public class AddSlaves extends Activity implements NfcAdapter.OnNdefPushCompleteCallback, NfcAdapter.CreateNdefMessageCallback{
//The array lists to hold our messages
private ArrayList<String> messagesToSendArray = new ArrayList<>();
private ArrayList<String> messagesReceivedArray = new ArrayList<>();
//Text boxes to add and display our messages
private EditText txtBoxAddMessage;
private TextView txtReceivedMessages;
private TextView txtMessagesToSend;
private NfcAdapter mNfcAdapter;
private void updateTextViews() {
txtReceivedMessages.setText("Messages Received:\n");
//Populate our list of messages we have received
if (messagesReceivedArray.size() > 0) {
for (int i = 0; i < messagesReceivedArray.size(); i++) {
txtReceivedMessages.append(messagesReceivedArray.get(i));
txtReceivedMessages.append("\n");
}
}
}
//Save our Array Lists of Messages for if the user navigates away
@Override
public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putStringArrayList("lastMessagesReceived",messagesReceivedArray);
}
//Load our Array Lists of Messages for when the user navigates back
@Override
public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
messagesReceivedArray = savedInstanceState.getStringArrayList("lastMessagesReceived");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_slaves);
txtReceivedMessages = (TextView) findViewById(R.id.txtMessagesReceived);
Button btnAddMessage = (Button) findViewById(R.id.buttonAddMessage);
//Check if NFC is available on device
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if(mNfcAdapter != null) {
//Handle some NFC initialization here
}
else {
Toast.makeText(this, "NFC not available on this device",
Toast.LENGTH_SHORT).show();
}
//Check if NFC is available on device
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if(mNfcAdapter != null) {
//This will refer back to createNdefMessage for what it will send
mNfcAdapter.setNdefPushMessageCallback(this, this);
//This will be called if the message is sent successfully
mNfcAdapter.setOnNdefPushCompleteCallback(this, this);
}
}
@Override
public NdefMessage createNdefMessage(NfcEvent event) {
//This will be called when another NFC capable device is detected.
return null;
}
@Override
public void onNdefPushComplete(NfcEvent event) {
//This is called when the system detects that our NdefMessage was
//Successfully sent.
messagesToSendArray.clear();
}
private void handleNfcIntent(Intent NfcIntent) {
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(NfcIntent.getAction())) {
Parcelable[] receivedArray =
NfcIntent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if(receivedArray != null) {
messagesReceivedArray.clear();
NdefMessage receivedMessage = (NdefMessage) receivedArray[0];
NdefRecord[] attachedRecords = receivedMessage.getRecords();
for (NdefRecord record:attachedRecords) {
String string = new String(record.getPayload());
//Make sure we don't pass along our AAR (Android Application Record)
if (string.equals(getPackageName())) { continue; }
messagesReceivedArray.add(string);
}
Toast.makeText(this, "Received " + messagesReceivedArray.size() +
" Messages", Toast.LENGTH_LONG).show();
updateTextViews();
}
else {
Toast.makeText(this, "Received Blank Parcel", Toast.LENGTH_LONG).show();
}
}
}
@Override
public void onNewIntent(Intent intent) {
handleNfcIntent(intent);
}
@Override
public void onResume() {
super.onResume();
updateTextViews();
handleNfcIntent(getIntent());
}
}
最佳答案
您的发件人 Activity 代码中存在一些问题:
您存储了
messagesToSendArray
,但实际上您从未用数据填充此数组列表(即messagesToSendArray.size()
始终为 0)。由于每当调用createNdefMessage()
时您都会重新创建 NDEF 消息,因此无需保存和恢复messagesToSendArray
。您写道,您希望在一个 Activity 中发送 NDEF 消息,但您希望在另一个 Activity 中接收 NFC 事件。但是,您注册了您的发送者 Activity 以在 list 中接收 NDEF_DISCOVERED 事件。如果您不想接收和处理这些事件,则无需在 list 中使用 NDEF_DISCOVERED Intent 过滤器。
此外,无需在您的发送者 Activity 中处理 NDEF_DISCOVERED Intent (即您可以安全地删除方法
onNewIntent()
和handleNfcIntent()
).在 Jelly Bean 以下的 Android 版本中,您创建了一个结构无效的 NFC 论坛文本记录。文本 RTD 需要一个以表单编码的有效负载(另请参阅 this post )
+----------+---------------+--------------------------------------+ | Status | Language Code | Text | | (1 byte) | (n bytes) | (m bytes) | +----------+---------------+--------------------------------------+
whereStatus
equals to the lengthn
of theLanguage Code
if theText
is UTF-8 encoded andLanguage Code
is an IANA language code (e.g. "en" for English). Consequently, the proper way to encode that record would be:public static NdefRecord createTextRecord(String language, String text) { byte[] languageBytes; byte[] textBytes; try { languageBytes = language.getBytes("US-ASCII"); textBytes = text.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { throw new AssertionError(e); } byte[] recordPayload = new byte[1 + (languageBytes.length & 0x03F) + textBytes.length]; recordPayload[0] = (byte)(languageBytes.length & 0x03F); System.arraycopy(languageBytes, 0, recordPayload, 1, languageBytes.length & 0x03F); System.arraycopy(textBytes, 0, recordPayload, 1 + (languageBytes.length & 0x03F), textBytes.length); return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, null, recordPayload); }
我不清楚为什么在 Jelly Bean 及以上版本的 Android 版本上创建 NFC 论坛文本记录,而在 Jelly Bean 及更高版本上创建 MIME 类型记录。您应该保持一致并在所有平台上创建相同的记录类型(请参阅 Method NdefRecord.createTextRecord("en" , "string") not working below API level 21 ):
String text = "192.168.1.100"; String language = "en"; NdefRecord record; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { record = NdefRecord.createTextRecord(language, text); } else { record = createTextRecord(language, text); }
最后,在
createRecords()
中创建数组records
asNdefRecord[] records = new NdefRecord[1];
因此,该数组在索引 0 处有一个可访问元素。但是,您稍后尝试访问元素 1:
records[1] = record;
这会导致
IndexOutOfBounds
异常。由于createRecords()
由 Android 通过createNdefMessage()
回调调用,回调失败(由于运行时异常)并且 Android 不会使用您的 NDEF 消息。相反,Android 将为您的应用使用默认的 NDEF 消息。此默认 NDEF 消息包含一个 Android 应用程序记录,它将导致您的主要 Activity 被调用(因为您的其他任何 Activity 都没有注册以针对默认 NDEF 消息的特定内容启动);见NFC tag detection is not calling onNewIntent and it's Launching From Main Activity .因此,您需要将存储新创建的 NDEF 记录的records
中的偏移量更改为 0:records[0] = record;
此外,您需要删除该行
records[messagesToSendArray.size()] = NdefRecord.createApplicationRecord(getPackageName());
因为这会用 Android 应用程序记录覆盖先前存储在索引 0 处的 NDEF 记录(
messagesToSendArray.size()
为 0)。同样,这将导致您的主要 Activity 开始,因为您没有在 list 中注册该特定记录类型。
最后,如果你想拒绝推送,除非用户在接收 Activity 中,你应该考虑使用前台调度系统。在这种情况下,您将从 list 中完全删除所有 NDEF_DISCOVERED Intent 过滤器,而是将每个 Activity (接收者、发送者、和 main)注册到前台调度系统。在接收器中,您将通过 onNewIntent()
接收 NDEF 消息。在发件人和主要 Activity 中,您只需忽略并丢弃任何收到的 NDEF 消息。参见 Android app enable NFC only for one Activity举个例子。
关于android - 接收到 NFC 后保持当前 Activity ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45598237/