Issue
I have a problem with Activity lifecycle and NFC:
I have a MainActivity with the AndroidManifest.xml entry:
<activity
android:name=".ui.main.MainActivity"
android:finishOnTaskLaunch="true"
android:launchMode="singleTask"
android:theme="@style/AppTheme.NoActionBar">
<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" />
<data android:mimeType="application/androidbeam" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/nfctag" />
</intent-filter>
<meta-data
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" />
</activity>
where launchMode="singleTask" is used for NFC to prevent multiple MainActivity instances.
In MainActivity I have the following code:
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Timber.d("onCreate");
setContentView(R.layout.activity_main);
handleIntent(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
Timber.d("OnNewIntent");
handleIntent(intent);
}
private void handleIntent(Intent intent){
String action = intent.getAction();
String intent_type = intent.getType();
Timber.d("Intent action:" + action + "\n " + "Intent type:" + intent_type);
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
// Handle data from intent.getParcelableExtra()
Timber.d("onNFCDataReaded");
}
// and implementing creating of activity here
}
@Override
protected void onResume() {
super.onResume();
Timber.d("onResume");
enableNFCDispatch();
}
@Override
protected void onPause() {
Timber.d("onPause");
super.onPause();
disableNFCDispatch();
}
@Override
protected void onDestroy() {
super.onDestroy();
Timber.d("OnDestroy");
}
@Override
public void onBackPressed() {
super.onBackPressed();
Timber.d("OnBackPressed");
}
}
Everything works as expected, except for one use case:
When I am opening the application first with Android Beam or an NFC tag, onCreate() is called and it passes getIntent() to handleIntent() with the data received from another phone or an NFC tag. This works fine.
But after that, when I
click onBackPressed button inside MainActivity (i.e. exiting the application), and
then hold the Home button and in the overview screen select my application,
my application is opened again and onCreate() is called again. However, getIntent() returns the old intent with same data (intent.getAction(), intent.getParcelableExtra()) as I got with Android Beam or NFC tag!
I don't understand why! I expect to receive a new intent; the same as if the app is created when I click the application icon.
Can somebody help me with this?
Here is my MainActivity lifecycle:
MainActivity: onCreate
MainActivity: handleIntent
MainActivity: Intent action: android.nfc.action.NDEF_DISCOVERED
Intent type: application/androidbeam
MainActivity: onNFCDataReaded
MainActivity: OnResume
MainActivity: OnBackPressed
MainActivity: onPause
MainActivity: OnDestroy
//After that, I am holding Home Button and selecting my application from
//OverViewScreen, and getting next Log:
MainActivity: onCreate
MainActivity: handleIntent
MainActivity: Intent action:android.nfc.action.NDEF_DISCOVERED
Intent type:application/androidbeam
- // I do not expect it here !!!!!
MainActivity: onNFCDataReaded
MainActivity: OnResume
Solution
This is expected behavior. When you bring your activity to the background and later open the activity again from history (long-press home key), Android will recreate the previous activity stack and the activity will be launched with the same parameters as it was opened before. I.e. if it was launched with intent NDEF_DISCOVERED, it will, again, receive that intent.
However, you can easily detect if the activity was launched with the original intent or if it was launched from history. In the latter case, Android adds the flag FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY to the intent. Consequently, you can test for this flag in your handleIntent() method:
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()) ||
NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
...
}
}
Answered By - Michael Roland
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.