我正在编写一个可读取和写入标签的Android应用程序。当我读取所有内容时,一切正常,当我尝试将数据保存在nfc标记上时,标记第一个读取的数据并再次打开活动,如何阻止意图读取并正确保存数据?
清单
<activity
android:name=".DeviceDetails.DeviceDetailsMain_NFC">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<meta-data
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" />
</activity>
这是我的活动代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.device_details_activity_main);
mDatabaseHelper = new DatabaseHelper(DeviceDetailsMain_NFC.this);
preferences = getSharedPreferences("DevDetails", MODE_PRIVATE);
context = this;
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
readFromIntent(getIntent());
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
writeTagFilters = new IntentFilter[] { tagDetected };
}
private void setupViewPager(ViewPager viewPager, String DEV_ID) {
SectionsPageAdapter adapter = new SectionsPageAdapter(getSupportFragmentManager());
adapter.addFragment(new Tab1Fragment(), getResources().getString(R.string.frag_ddm_device));
if(mDatabaseHelper.checkParameters(DEV_ID))adapter.addFragment(new Tab4Fragment(), getResources().getString(R.string.frag_ddm_parameters));
if(mDatabaseHelper.isDevice(DEV_ID)) adapter.addFragment(new Tab3Fragment(), getResources().getString(R.string.frag_ddm_events));
if(mDatabaseHelper.getModelID(DEV_ID) != null) adapter.addFragment(new Tab2Fragment(), getResources().getString(R.string.frag_ddm_model));
viewPager.setAdapter(adapter);
}
public boolean writeNFC(String ID){
if(myTag != null) {
try {
write(ID, myTag);
return true;
} catch (IOException e) {
return false;
} catch (FormatException e) {
return false;
}
}else{
return false;
}
}
/**********************************Read From NFC Tag***************************/
private void readFromIntent(Intent intent) {
String action = intent.getAction();
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage[] msgs = null;
if (rawMsgs != null) {
msgs = new NdefMessage[rawMsgs.length];
for (int i = 0; i < rawMsgs.length; i++) {
msgs[i] = (NdefMessage) rawMsgs[i];
}
}
if (msgs == null || msgs.length == 0) return;
String text = "";
byte[] payload = msgs[0].getRecords()[0].getPayload();
String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; // Get the Text Encoding
int languageCodeLength = payload[0] & 0063; // Get the Language Code, e.g. "en"
// String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
try {
// Get the Text
text = new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);
} catch (UnsupportedEncodingException e) {
Log.e("UnsupportedEncoding", e.toString());
}
saveData(text);
mViewPager = findViewById(R.id.view_pager);
setupViewPager(mViewPager, text);
TabLayout tabLayout = findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
String devName = mDatabaseHelper.getDevName(text);
if (devName != null) {
getSupportActionBar().setTitle(devName);
} else {
getSupportActionBar().setTitle("");
}
}else{
DEV_ID = preferences.getString("devID", "");
mViewPager = findViewById(R.id.view_pager);
setupViewPager(mViewPager, DEV_ID);
TabLayout tabLayout = findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
String devName = mDatabaseHelper.getDevName(DEV_ID);
if (devName != null) {
getSupportActionBar().setTitle(devName);
} else {
getSupportActionBar().setTitle("");
}
}
}
private void saveData(String dane) {
SharedPreferences.Editor preferencesEditor = preferences.edit();
preferencesEditor.putString("devID", dane);
preferencesEditor.commit();
}
/**********************************Write to NFC Tag****************************/
private void write(String text, Tag tag) throws IOException, FormatException {
NdefRecord[] records = { createRecord(text) };
NdefMessage message = new NdefMessage(records);
// Get an instance of Ndef for the tag.
Ndef ndef = Ndef.get(tag);
// Enable I/O
ndef.connect();
// Write the message
ndef.writeNdefMessage(message);
// Close the connection
ndef.close();
}
private NdefRecord createRecord(String text) throws UnsupportedEncodingException {
String lang = "en";
byte[] textBytes = text.getBytes();
byte[] langBytes = lang.getBytes(StandardCharsets.US_ASCII);
int langLength = langBytes.length;
int textLength = textBytes.length;
byte[] payload = new byte[1 + langLength + textLength];
// set status byte (see NDEF spec for actual bits)
payload[0] = (byte) langLength;
// copy langbytes and textbytes into payload
System.arraycopy(langBytes, 0, payload, 1, langLength);
System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);
NdefRecord recordNFC = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload);
return recordNFC;
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
readFromIntent(intent);
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
}
}
@Override
public void onPause(){
super.onPause();
WriteModeOff();
}
@Override
public void onResume(){
super.onResume();
WriteModeOn();
}
/**********************************Enable Write********************************/
private void WriteModeOn(){
writeMode = true;
nfcAdapter.enableForegroundDispatch(this, pendingIntent, writeTagFilters, null);
}
/**********************************Disable Write*******************************/
private void WriteModeOff(){
writeMode = false;
nfcAdapter.disableForegroundDispatch(this);
}
}
片段代码:
btnWrite.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Handler handler = new Handler();
final int delay = 100; //milliseconds
final AlertDialog alertDialog = new AlertDialog.Builder(context).create();
alertDialog.setTitle(R.string.save_to_NFC_tag);
alertDialog.setMessage(getContext().getResources().getString(R.string.approach_an_NFC_Tag));
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, getContext().getResources().getString(R.string.ok),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
handler.removeCallbacks(runnable);
dialog.dismiss();
}
});
alertDialog.show();
handler.postDelayed(runnable = new Runnable(){
public void run(){
if (deviceDetailsMain_nfc.writeNFC(DEV_ID)) {
alertDialog.setMessage(getContext().getResources().getString(R.string.record_completed));
handler.removeCallbacks(runnable);
}
handler.postDelayed(this, delay);
}
}, delay);
}
});
我有一个运行4个片段的活动,在活动中读取代码,并且从片段中调用写作机制
对于写入,我不会使用enableForegroundDispatch
方法,它会误导用户将卡移出范围太快,从而导致在实际用户使用时出现许多写入错误和数据损坏。
这是因为声音提示会在操作系统读取卡后立即发生,而您的代码才有机会对其进行写入。
我会在要控制声音提示的地方使用enableReaderMode
。
更新请注意,使用enabledReaderMode
时,您仍然可以在清单中放置Intent过滤器,以要求Android OS在看到特定类型的标签时启动您的应用,而清单Intent过滤器生成的Intent始终在Activity的onCreate
方法中进行处理无论您在“活动”中如何处理卡片。
[enableForegroundDispatch
同样也不可靠读取,因为操作系统在看起来像没有窗口的活动中处理NFC读取,因此您的活动在读取时会暂停”
我已经通过enableForegroundDispatch
进行了真实的用户测试,当您的应用位于前台时,该标签进入范围,您的应用被暂停,该标签超出范围,然后回到范围之前,您的应用已经机会被恢复,因此OS认为没有东西在等待它的Intent,因此打开它自己的窗口,显示NDEF数据的基本屏幕,而不是尝试将Intent传递给仍暂停的Activity。
另一个建议是,如果您可以轻松地使用NDEF格式,因为操作系统知道NDEF会尝试使用它来做事,使用您自己的格式意味着操作系统不太可能干扰您的操作。但是,如果您要写的数据多于一页数据,则会更加复杂,但是您确实可以获得更好的错误处理能力。
使用enableReaderMode
,读卡时您的应用不会暂停(相反,卡交互是在应用中的单独线程中处理的),您可以控制声音,因此可以在完成声音后播放声音而不是任务完成时写。
答案enableReaderMode
写页面中的低级读取https://stackoverflow.com/a/59397667/2373819的示例与读取在结构上没有太大差异。
更新:重新读取您的代码,似乎在编写时就假定该标签在范围内。因为标签可以轻松,频繁地进入或离开范围,所以一旦触发onNewIntent
,就可以更加可靠地进行写入。
您应该将onNewIntent
视为一个通知,告知您标签在您可以读写标签的范围内(在enableReaderMode
方法中,它被称为onTagDiscovered
,因为它的确是这样。)