LeeJ
LeeJ

Reputation: 31

Android NFC activity being relaunched even though its on the top of the stack

I'm guessing most of you face palmed when you saw this title, and thought we've seen this before well I agree, but I've tried everything to solve this issue and it wont remedy. So here goes.

My app can be launched from the home screen(icon) and everything works OK it scans a NFC tag and sends the relevant data to the server. However what I also want is for the App to be launched from NFC tag, which it does no problem. However! when the app is launched via the NFC tag you then remove the phone and re-present it to the tag it should then read the tag and send the data to the server. Exactly the same behaviour as launching the app via the the icon, but when you scan the NFC tag this time a new instance of the app is launched which ultimately kicks the current instance down the stack, the version of the instance that was busy reading the tag so I get a ANR.

in a nutshell:
from home screen -> scan a tag -> app launches.
you then rescan the tag->
The current instance of the app disappears to be replaced by a new instance. I want the previous instance to stay where it was and work.

A few guesses from me at this point would be that: -The NFC is not getting properly registered to app, hence the the OS doing default behaviour.
-There is a flag not being set correctly when launched via a NFC tag telling the OS the activity does not need to relaunched.

anyway here's the code:

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

<intent-filter>
            <action android:name="android.nfc.action.NDEF_DISCOVERED" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="http"android:host="@string/URL_for_intent_filtering" android:pathPrefix="/id/" />

//Procedure of NFC startup called from OnCreate
private void startNFC()
{
    mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
    if(! mNfcAdapter.isEnabled())//check the NFC is switched on
    {
        mMainActivityHandler.sendEmptyMessage(NFC_DISABLED);
    }

    //its ok to carry on and instantiate the NFC even though its not enabled.
    if(mNfcAdapter != null)
    {
        int requestID = (int) System.currentTimeMillis();
        mPendingIntent = PendingIntent.getActivity(this, requestID, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_UPDATE_CURRENT);

        IntentFilter intentF = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        intentF.addDataScheme("http");

        intentfilter = new IntentFilter[] {intentF};



        if(DEBUG) Log.i("DEBUG","+++++++++++++++++++++++++++++++++++++++++++++++ NFC HAS BEEN STARTED");

    }else
    {
        //we have a problem with the NFC adapter probably because the device doesn't have one.
        if(DEBUG) Log.i("DEBUG","+++++++++++++++++++++++++++++++++++++++++++++++ NFC HAS FAILED");
        mMainActivityHandler.sendEmptyMessage(NFC_FAILED);
    }
}

@Override
protected void onPause()
{
    if(DEBUG) Log.i("MA","+++++++++++++++++++++++++++++++++++++++ ON PAUSE");
    try{
        mNfcAdapter.disableForegroundDispatch(this);
    }catch(Exception e)
    {

    }
    super.onPause();
}

//and here we should reinstate the NFC adapter
@Override
protected void onResume()
{
    if(DEBUG) Log.i("MA","+++++++++++++++++++++++++++++++++++++++ ON RESUME");

    //setupDataListener(true);
    setupServerComms(getApplicationContext());
    //mNfcAdapter.enableForegroundDispatch(this,mPendingIntent,intentfilter,null);
    mNfcAdapter.enableForegroundDispatch(this,mPendingIntent,null,null);
    super.onResume();
}

Upvotes: 3

Views: 2227

Answers (2)

Talls
Talls

Reputation: 117

So what you want is for the app to catch the intent and then read the information and do something with it correct? Well you have a pending intent that is used to do this but your setup seems a little different from what I usually do. Here is an example of how I use a pending intent to catch the tag data (from there you can do whatever you want like send it to a server):

Class example{

NfcAdapter adapter;
Tag motor;
String FileName;
PendingIntent detectTag;
IntentFilter NFC;
IntentFilter [] Catcher;
String [][] TechList;
TextView readToField;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_activity);

// Catch NFC detects
adapter = NfcAdapter.getDefaultAdapter(this);
detectTag = PendingIntent.getActivity(this,0,new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
NFC = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
Catcher = new IntentFilter[] {NFC,};
TechList = new String [][]{new String[]{android.nfc.tech.NfcV.class.getName()}};
}

public void onNewIntent(Intent intent)
{
    super.onNewIntent(intent);
    motor = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    Bridge bridge = (Bridge) getApplication();
    bridge.setCurrentTag(motor);
}

public void onPause()
{
    super.onPause();
    adapter.disableForegroundDispatch(this);
}

public void onResume()
{
    super.onResume();
    adapter.enableForegroundDispatch(this,detectTag ,Catcher , TechList);
}
}

The Bridge object is just a class I use to save the tag information so I can send information to tags from other (behind the scenes) classes.

Finally, I have always been told that for onResume and onPause you should call the super.method first.

Upvotes: 1

tasomaniac
tasomaniac

Reputation: 10342

Just add this line in your AndroidManifest.xml into your Activity and you are probably done.

        android:launchMode="singleTask"

Upvotes: 5

Related Questions