A share-target Activity that must not run twice: why it finishes itself when Android restores it A developer of the Android app Auto UPI QR described a restore-safe pattern for share-target Activities: by checking savedInstanceState == null in onCreate and calling finish() on any restore, the app prevents a payment-adjacent share flow from re-running after Android recreates the Activity with its original intent. The app also finishes on unrecognized intents, distinguishes 'no QR found' from read errors, and uses the API 33+ typed getParcelableExtra overload for EXTRA_STREAM. Disclosure: I'm the developer of the app described here, and this post was drafted and published by an AI agent from the project's source code. Auto UPI QR https://play.google.com/store/apps/details?id=com.ashwar.autoupiqr&referrer=utm source%3Ddevto%26utm medium%3Darticle lives in the Android share menu. You share a QR picture or a upi:// link as text to it, it reads the payee details, and it hands the link to your own UPI app. The entry point is a 61-line Activity. Most of it is routine; one line is there because of what happens when Android takes the Activity away and brings it back. A share-target Activity is launched with an Intent carrying the shared image. If the system kills your process while the Activity is in the background low memory, the user switching apps for a while , Android recreates the Activity later, and onCreate runs again with the same original intent , plus a non-null savedInstanceState . For an Activity that shows a picture, that is fine. For one that acts on the intent, it means the action can run a second time with nobody having asked. For a payment-adjacent flow that is the wrong default: the user comes back to the phone and a pay sheet for an old QR appears out of nowhere. override fun onCreate savedInstanceState: Bundle? { super.onCreate savedInstanceState if savedInstanceState = null { finish ; return } ... } A fresh share always arrives with savedInstanceState == null . A restore never does. So the rule is: act only on a fresh launch, and close quietly on a restore. If the user still wants to pay, sharing the QR again takes two taps, and that second share is a deliberate act. php when { action == Intent.ACTION SEND && type.startsWith "image/" - { val uri = streamUri intent ?: return finish handleImage uri } action == Intent.ACTION SEND && type.startsWith "text/" - { val qr = UpiQr.findIn intent.getStringExtra Intent.EXTRA TEXT if qr == null { toast R.string.toast no upi qr ; finish } else paySheet.handle qr { finish } } else - finish } Three small decisions are worth copying: else - finish . A share target should never sit open on an intent it doesn't understand. finish . Found , NoUpiQr or Error . "This picture has no UPI QR" and "something went wrong reading it" are different toasts, because they lead to different next steps for the user. EXTRA STREAM is read differently on newer Android: private fun streamUri intent: Intent : Uri? = if Build.VERSION.SDK INT = 33 intent.getParcelableExtra Intent.EXTRA STREAM, Uri::class.java else intent.getParcelableExtra Intent.EXTRA STREAM The typed overload API 33+ checks the class for you; the old one is deprecated, hence the narrowly scoped @Suppress "DEPRECATION" on this one function instead of the whole file. A null Uri is simply finish . handleImage launches in lifecycleScope and calls the scanner as a suspend function. Because the scope is tied to the Activity, a user who backs out mid-scan cancels the work rather than leaving it to call paySheet.handle on a dead Activity. savedInstanceState == null . @Suppress "DEPRECATION" to the one function that needs it. Auto UPI QR is on Google Play: https://play.google.com/store/apps/details?id=com.ashwar.autoupiqr https://play.google.com/store/apps/details?id=com.ashwar.autoupiqr . It reads UPI QR codes from images and hands them to your own UPI app; it is not a bank and never sees your PIN. The restore-safe share handling and pay sheet described here are in the source for the next version; I don't claim which Play build contains them. Always check the payee name before entering your UPI PIN.