问题
I found a tutorial on how to read and write a NDEF NFC tag via a Toggle Button.
I wanted 2 separate buttons and after several days and some help (I am a newbie on Android), I have now managed to do that. I have 2 buttons, related to 2 activities. Clicking on read button will open the read activity and read my tag. Clicking on the write button will open the write activity, pop up the keyboard. I type the text I want to write but when I touch the tag, it sends me back to my main activity where my 2 buttons are. Puzzled...
If I create a new app with only the writing code, I can write perfectly (and then read from another app) so I know the code works.
I have tried to disable my read button, but it doesn't change anything.
It must be a small thing but after several hours on it, I still cant figure it out. Could somebody please help? The code is below. Cheers.
public class MainActivity extends Activity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(this);
Button button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
Intent detailIntent = new Intent(this, ReadActivity.class);
startActivity(detailIntent);
break;
case R.id.button2:
Intent detailIntent2 = new Intent(this, WriteActivity3.class);
startActivity(detailIntent2);
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
public class ReadActivity extends Activity {
public static final String MIME_TEXT_PLAIN = "text/plain";
public static final String TAG = "NfcDemo";
private TextView mTextView;
private NfcAdapter mNfcAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_read);
mTextView = (TextView) findViewById(R.id.textView_explanation);
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (mNfcAdapter == null) {
// Stop here, we definitely need NFC
Toast.makeText(this, "This device doesn't support NFC.",
Toast.LENGTH_LONG).show();
finish();
return;
}
if (!mNfcAdapter.isEnabled()) {
mTextView.setText("NFC is disabled.");
} else {
mTextView.setText("Touch a Tag");
}
handleIntent(getIntent());
}
@Override
protected void onResume() {
super.onResume();
/**
* It's important, that the activity is in the foreground (resumed). Otherwise
* an IllegalStateException is thrown.
*/
setupForegroundDispatch(this, mNfcAdapter);
}
@Override
protected void onPause() {
/**
* Call this before onPause, otherwise an IllegalArgumentException is thrown as well.
*/
stopForegroundDispatch(this, mNfcAdapter);
super.onPause();
}
@Override
protected void onNewIntent(Intent intent) {
/**
* This method gets called, when a new Intent gets associated with the current activity instance.
* Instead of creating a new activity, onNewIntent will be called. For more information have a look
* at the documentation.
*
* In our case this method gets called, when the user attaches a Tag to the device.
*/
handleIntent(intent);
}
private void handleIntent(Intent intent) {
String action = intent.getAction();
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
String type = intent.getType();
if (MIME_TEXT_PLAIN.equals(type)) {
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
new NdefReaderTask().execute(tag);
} else {
Log.d(TAG, "Wrong mime type: " + type);
}
} else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {
// In case we would still use the Tech Discovered Intent
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String[] techList = tag.getTechList();
String searchedTech = Ndef.class.getName();
for (String tech : techList) {
if (searchedTech.equals(tech)) {
new NdefReaderTask().execute(tag);
break;
}
}
}
}
public static void setupForegroundDispatch(final Activity activity, NfcAdapter adapter) {
final Intent intent = new Intent(activity.getApplicationContext(), activity.getClass());
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
final PendingIntent pendingIntent = PendingIntent.getActivity(activity.getApplicationContext(), 0, intent, 0);
IntentFilter[] filters = new IntentFilter[1];
String[][] techList = new String[][]{};
// Notice that this is the same filter as in our manifest.
filters[0] = new IntentFilter();
filters[0].addAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
filters[0].addCategory(Intent.CATEGORY_DEFAULT);
try {
filters[0].addDataType(MIME_TEXT_PLAIN);
} catch (MalformedMimeTypeException e) {
throw new RuntimeException("Check your mime type.");
}
adapter.enableForegroundDispatch(activity, pendingIntent, filters, techList);
}
public static void stopForegroundDispatch(final Activity activity, NfcAdapter adapter) {
adapter.disableForegroundDispatch(activity);
}
/**
* Background task for reading the data. Do not block the UI thread while reading.
*/
private class NdefReaderTask extends AsyncTask<Tag, Void, String> {
@Override
protected String doInBackground(Tag... params) {
Tag tag = params[0];
Ndef ndef = Ndef.get(tag);
if (ndef == null) {
// NDEF is not supported by this Tag.
return null;
}
NdefMessage ndefMessage = ndef.getCachedNdefMessage();
NdefRecord[] records = ndefMessage.getRecords();
for (NdefRecord ndefRecord : records) {
if (ndefRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN && Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) {
try {
return readText(ndefRecord);
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unsupported Encoding", e);
}
}
}
return null;
}
private String readText(NdefRecord record) throws UnsupportedEncodingException {
/*
* See NFC forum specification for "Text Record Type Definition" at 3.2.1
*
* http://www.nfc-forum.org/specs/
*
* bit_7 defines encoding
* bit_6 reserved for future use, must be 0
* bit_5..0 length of IANA language code
*/
byte[] payload = record.getPayload();
// Get the Text Encoding
// String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16";
String textEncoding = new String ("");
if ((payload[0] & 128) == 0) {
textEncoding = "UTF-8";
} else {
textEncoding = "UTF-16";
}
// Get the Language Code
int languageCodeLength = payload[0] & 63;
// String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
// e.g. "en"
// Get the Text
return new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);
}
@Override
protected void onPostExecute(String result) {
if (result != null) {
mTextView.setText("The content of the tag is : " + result);
}
}
}
}
public class WriteActivity3 extends Activity {
NfcAdapter nfcAdapter;
EditText txtTagContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_write_activity3);
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
txtTagContent = (EditText)findViewById(R.id.txtTagContent);
}
@Override
protected void onResume() {
super.onResume();
enableForegroundDispatchSystem();
}
@Override
protected void onPause() {
super.onPause();
disableForegroundDispatchSystem();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent.hasExtra(NfcAdapter.EXTRA_TAG)) {
Toast.makeText(this, "Tag detected...", Toast.LENGTH_SHORT).show();
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
// Adding the time
Date now = new Date();
//Convert current time to String using specified format
String format = " dd-MMM-yyyy HH:mm:ss";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format, Locale.US);
String formattedNow = simpleDateFormat.format(now);
NdefMessage ndefMessage = createNdefMessage(txtTagContent.getText() + formattedNow);
writeNdefMessage(tag, ndefMessage);
}
}
private void enableForegroundDispatchSystem() {
Intent intent = new Intent(this, MainActivity.class).addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
IntentFilter[] intentFilters = new IntentFilter[]{};
nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilters, null);
}
private void disableForegroundDispatchSystem() {
nfcAdapter.disableForegroundDispatch(this);
}
private void formatTag(Tag tag, NdefMessage ndefMessage) {
try {
NdefFormatable ndefFormatable = NdefFormatable.get(tag);
if (ndefFormatable == null) {
Toast.makeText(this, "Tag is not ndef formatable!", Toast.LENGTH_SHORT).show();
return;
}
ndefFormatable.connect();
ndefFormatable.format(ndefMessage);
ndefFormatable.close();
Toast.makeText(this, "Message writen !", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Log.e("formatTag", e.getMessage());
}
}
private void writeNdefMessage(Tag tag, NdefMessage ndefMessage) {
try {
if (tag == null) {
Toast.makeText(this, "Tag object cannot be null", Toast.LENGTH_SHORT).show();
return;
}
Ndef ndef = Ndef.get(tag);
if (ndef == null) {
// format tag with the ndef format and writes the message.
formatTag(tag, ndefMessage);
} else {
ndef.connect();
if (!ndef.isWritable()) {
Toast.makeText(this, "Tag is not writable!", Toast.LENGTH_SHORT).show();
ndef.close();
return;
}
ndef.writeNdefMessage(ndefMessage);
ndef.close();
Toast.makeText(this, "Tag writen!", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e("writeNdefMessage", e.getMessage());
}
}
private NdefRecord createTextRecord(String content) {
try {
byte[] language;
language = Locale.getDefault().getLanguage().getBytes("UTF-8");
final byte[] text = content.getBytes("UTF-8");
final int languageSize = language.length;
final int textLength = text.length;
final ByteArrayOutputStream payload = new ByteArrayOutputStream(1 + languageSize + textLength);
payload.write((byte) (languageSize & 0x1F));
payload.write(language, 0, languageSize);
payload.write(text, 0, textLength);
return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload.toByteArray());
} catch (UnsupportedEncodingException e) {
Log.e("createTextRecord", e.getMessage());
}
return null;
}
private NdefMessage createNdefMessage(String content) {
NdefRecord ndefRecord = createTextRecord(content);
NdefMessage ndefMessage = new NdefMessage(new NdefRecord[]{ndefRecord});
return ndefMessage;
}
public void tglReadWriteOnClick(View view){
txtTagContent.setText("");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_write_activity3, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="uk.co.masystems.tagreader" >
<uses-permission android:name="android.permission.NFC" />
<uses-feature
android:name="android.hardware.nfc"
android:required="true" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".ReadActivity"
android:label="@string/app_name" >
// only for NDEF alone
<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=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".WriteActivity"
android:label="@string/title_activity_write" >
</activity>
<activity
android:name=".WriteActivity2"
android:label="@string/title_activity_write_activity2" >
</activity>
<activity
android:name=".WriteActivity3"
android:label="@string/title_activity_write_activity3" >
</activity>
</application>
</manifest>
回答1:
OK, I found it. In my WriteActivite3.java, inside the private void enableForegroundDispatchSystem() {} I call for MainActivity and not for WriteActivity3. All working now.
来源:https://stackoverflow.com/questions/30462444/android-nfc-writing-doesnt-work-with-2-activities-but-works-with-1