3

I am using androidx.biometric:biometric:1.0.0-alpha04 library in my project. But I could see many crashes in crashlytics as well as play-store when I am trying to authenticate using BiometricPrompt. Crash happens at below code

myBiometricPrompt.authenticate(promptInfo, mcryptoObject!!)

Below is the stack trace from crashlytics

Fatal Exception: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
   at androidx.fragment.app.FragmentManagerImpl.checkStateLoss(FragmentManagerImpl.java:2080)
   at androidx.fragment.app.FragmentManagerImpl.enqueueAction(FragmentManagerImpl.java:2106)
   at androidx.fragment.app.BackStackRecord.commitInternal(BackStackRecord.java:683)
   at androidx.fragment.app.BackStackRecord.commit(BackStackRecord.java:637)
   at androidx.fragment.app.DialogFragment.show(DialogFragment.java:144)
   at androidx.biometric.BiometricPrompt.authenticateInternal(BiometricPrompt.java:499)
   at androidx.biometric.BiometricPrompt.authenticate(BiometricPrompt.java:452)
   at com.transfast.transfast.biometric.BiometricHelper$startAuth$2.run(BiometricHelper.java:132)
   at android.os.Handler.handleCallback(Handler.java:790)
   at android.os.Handler.dispatchMessage(Handler.java:99)
   at android.os.Looper.loop(Looper.java:164)
   at android.app.ActivityThread.main(ActivityThread.java:7000)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)
Mangesh Kadam
  • 587
  • 5
  • 19
  • Did you find the root cause of the crashes? We're experiencing the same type of crashes, but we're unable to reproduce (it happens in 1% of our sessions). – Erik Haider Forsén Aug 30 '19 at 06:24
  • When are you calling this? lt looks very much like you are trying to call this in a wrong fragment state, although there is currently a problem with this library in such a case as well. – Javatar Sep 03 '19 at 12:09

1 Answers1

1

We found we could resolve this by explicitly checking for whether the current activity is in the resumed state:

FragmentActivity activity = ((FragmentActivity) activity);
Lifecycle lifecycle = activity.getLifecycle();
Lifecycle.State lifecycleState = lifecycle.getCurrentState();
if (lifecycleState != Lifecycle.State.RESUMED) {
    // don't
    return;
}

BiometricPrompt biometricPrompt = new BiometricPrompt(activity, mExecutor, callback);
biometricPrompt.authenticate(promptInfo);

it has to be RESUMED specifically, because STARTED can still allow the call to happen after onSaveInstanceState

See https://developer.android.com/topic/libraries/architecture/lifecycle

Wes Johnson
  • 3,063
  • 23
  • 32
  • Can you point out where "STARTED can still allow the call to happen after onSaveInstanceState" is stated in the documents? In the linked document, the code listed under the text - "For example, if the callback runs a fragment transaction after the activity state is saved, it would trigger a crash, so we would never want to invoke that callback." - uses STARTED as the suggested solution. – Shayla Sawchenko Jan 06 '20 at 23:11
  • Okay ! You are omitting the callback if it isn't in OnResume , but... you should still call it again right after it has resumed ? – Divesh May 06 '23 at 17:12