1

My Activity.onCreate() method is called twice when I use foreground NFC dispatching and re-install my app after force-stop. Detailed steps to reproduce this bug:

  1. Create the following Activity:
package com.example.sample

class MainActivity : AppCompatActivity() {
    private val nfcTechList: Array<Array<String>> = arrayOf(arrayOf(IsoDep::class.java.name))
    private val nfcIntentFilters: Array<IntentFilter> = arrayOf(IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED, "*/*"))

    private lateinit var nfcAdapter: NfcAdapter
    private lateinit var pendingIntent: PendingIntent

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("SAMPLE_TAG", "onCreate")
        setContentView(R.layout.activity_main)

        nfcAdapter = NfcAdapter.getDefaultAdapter(applicationContext)
        val nfcIntent = Intent(this, javaClass).apply {
            addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
        }
        pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            PendingIntent.getActivity(this, 0, nfcIntent, PendingIntent.FLAG_MUTABLE)
        } else {
            PendingIntent.getActivity(this, 0, nfcIntent, 0)
        }
    }

    override fun onResume() {
        super.onResume()
        Log.d("SAMPLE_TAG", "onResume")
        nfcAdapter.enableForegroundDispatch(this, pendingIntent, nfcIntentFilters, nfcTechList)
    }

    override fun onPause() {
        super.onPause()
        Log.d("SAMPLE_TAG", "onPause")
        nfcAdapter.disableForegroundDispatch(this)
    }
}
  1. Install and run this app on Android >= 12 and targetSdk = 33.
  2. Force-stop this app through settings and delete the app.
  3. Install and run the app again through this command: adb install app-debug.apk && adb shell am start -n "com.example.sample/com.example.sample.MainActivity" or run the app with Android Studio. (Note: if you run these 2 adb commands separately one after the other - the bug won't reproduce!).
  4. In logcat you'll see that onCreate() method was called twice:
14:20:55.419 22851 22851 D SAMPLE_TAG: onCreate
14:20:55.542 22851 22851 D SAMPLE_TAG: onResume
14:20:55.575 22851 22851 D SAMPLE_TAG: onPause
14:20:55.612 22851 22851 D SAMPLE_TAG: onCreate
14:20:55.640 22851 22851 D SAMPLE_TAG: onResume

I expect that Activity.onCreate() method will be called only once regardless of the way you run the app. I used the example of foreground NFC dispatching from official documentation, see https://developer.android.com/guide/topics/connectivity/nfc/advanced-nfc#foreground-dispatch

The actual result is that onCreate() & the following onResume() methods are called twice although it doesn't correspond with the Activity's lifecycle.

Xeniale
  • 11
  • 2

1 Answers1

0

The answer is to use enableReaderMode instead of the older as less reliable enableForegroundDispatch

enableReaderMode does not have to pause and resume your app and does not have interactions with your startup mode (which might be your problem), it also gives you more control and it helps you correctly not do NFC operations on the main UI thread as it automatically starts a new thread and is much more reliable especially for write operations.

An example of using enableReaderMode

Andrew
  • 8,198
  • 2
  • 15
  • 35
  • AFAIK if the tag has not been removed yet, the corresponding `disableReaderMode` method leads to the default NFC dispatching algorithm start, which leads to vibration, app choosing dialog or even Google Play launch (if a nfc tag has an Application Record). ForegroundDispatch system, howewer, does not have such behavior. The main question is - what happens with the whole app with such targetSdk. – Xeniale Jul 18 '23 at 08:37
  • Normally you only `enableReaderMode` in `onResume` and `disableReaderMode` in `onPause` so this is never a problem (this is same a the documented places to enable/disabled `enableForegroundDispatch`) . Also to provide a good user experience it is wise to use `enableReaderMode` even in other Activities in your App that don't use NFC so that they can silently ignore the NFC Tag, just in case the user leaves the NFC Tag under the phone and moves to another Activity (just have an empty `onTagDiscovered` if you don't want to do anything NFC – Andrew Jul 18 '23 at 19:53