You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[ktx] Construct PermissionsRequester from Fragment may cause that callbacks (requiresPermission, onPermissionDenied, etc.) are called after Fragment instance is already dead
#765
Open
omtians9425 opened this issue
Feb 26, 2022
· 4 comments
· May be fixed by #766
When we open and close the same Fragment that constructs PermissionRequester multiple times the callback passed by closed one's instance is called and this may cause a crash.
Open app then FirstFragment is launched as a root Fragment
Navigate to SecondFragment (PermissionsRequester is constructed here) with tapping "CLICK TO NEXT"
Back to FirstFragment
Navigate to SecondFragment again
Tap "REQUEST PERMISSION"
Tap "DENY" or "ALLOW"
App crashes (Toast is about to be shown in Fragment's Context with a permission result callback)
Stack trace:
Toast uses detached Context so java.lang.IllegalStateException: Fragment SecondFragment{9e09ebc} (c9cd8d4c-7acc-476a-90c8-7e882fc8dd69) not attached to a context. is shown
2022-02-25 01:27:24.555 21578-21578/com.example.omtians9425.permissionsdispatcherktxsample E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.omtians9425.permissionsdispatcherktxsample, PID: 21578
java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=1462789988, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {com.example.omtians9425.permissionsdispatcherktxsample/com.example.omtians9425.permissionsdispatcherktxsample.MainActivity}: java.lang.IllegalStateException: Fragment SecondFragment{9e09ebc} (c9cd8d4c-7acc-476a-90c8-7e882fc8dd69) not attached to a context.
at android.app.ActivityThread.deliverResults(ActivityThread.java:4360)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4402)
at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.IllegalStateException: Fragment SecondFragment{9e09ebc} (c9cd8d4c-7acc-476a-90c8-7e882fc8dd69) not attached to a context.
at androidx.fragment.app.Fragment.requireContext(Fragment.java:919)
at com.example.omtians9425.permissionsdispatcherktxsample.SecondFragment$onAttach$1.invoke(SecondFragment.kt:24)
at com.example.omtians9425.permissionsdispatcherktxsample.SecondFragment$onAttach$1.invoke(SecondFragment.kt:20)
at permissions.dispatcher.ktx.PermissionRequestViewModel$observe$1.onChanged(PermissionRequestViewModel.kt:33)
at permissions.dispatcher.ktx.PermissionRequestViewModel$observe$1.onChanged(PermissionRequestViewModel.kt:30)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:133)
at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:151)
at androidx.lifecycle.LiveData.setValue(LiveData.java:309)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
at permissions.dispatcher.ktx.PermissionRequestViewModel.notifyObserver(PermissionRequestViewModel.kt:43)
at permissions.dispatcher.ktx.PermissionRequestViewModel.postPermissionRequestResult(PermissionRequestViewModel.kt:20)
at permissions.dispatcher.ktx.PermissionRequestFragment$NormalRequestPermissionFragment.onRequestPermissionsResult(PermissionRequestFragment.kt:53)
at androidx.fragment.app.FragmentManager$9.onActivityResult(FragmentManager.java:2679)
at androidx.fragment.app.FragmentManager$9.onActivityResult(FragmentManager.java:2651)
at androidx.activity.result.ActivityResultRegistry.doDispatch(ActivityResultRegistry.java:392)
at androidx.activity.result.ActivityResultRegistry.dispatchResult(ActivityResultRegistry.java:351)
at androidx.activity.ComponentActivity.onRequestPermissionsResult(ComponentActivity.java:667)
at androidx.fragment.app.FragmentActivity.onRequestPermissionsResult(FragmentActivity.java:612)
at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:7608)
at android.app.Activity.dispatchActivityResult(Activity.java:7458)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4353)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4402)
at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
GIF with the above procedure
Expected
Permission result callbacks passed by Fragment that is alive (most recently opened one) are correctly called without any crashes.
Actual
App crashes with permission result callbacks being called passed by Fragment that is already dead.
If PermissionsRequster was constructed by Fragment, lambda passed into LiveData.observe will still be registered, and observing LiveData won't stop when the Fragment dies
When the same Fragment is reopened and the LiveData is updated, the previous lambda is called
The text was updated successfully, but these errors were encountered:
omtians9425
changed the title
[ktx] Construct PermissionsRequester from Fragment causes that callbacks (requiresPermission, onPermissionDenied, etc.) are called after Fragment instance is already dead
[ktx] Construct PermissionsRequester from Fragment may cause that callbacks (requiresPermission, onPermissionDenied, etc.) are called after Fragment instance is already dead
Mar 4, 2022
Overview
PermissionRequester
multiple times the callback passed by closed one's instance is called and this may cause a crash.Reproducible steps
FirstFragment
is launched as a root FragmentSecondFragment
(PermissionsRequester
is constructed here) with tapping "CLICK TO NEXT"FirstFragment
SecondFragment
againToast
is about to be shown in Fragment's Context with a permission result callback)Stack trace:
Toast uses detached Context so
java.lang.IllegalStateException: Fragment SecondFragment{9e09ebc} (c9cd8d4c-7acc-476a-90c8-7e882fc8dd69) not attached to a context.
is shownGIF with the above procedure
Expected
Actual
Environment
Hypothesis for the cause of the crash
PermissionsRequster
was constructed by Fragment or Activity.PermissionsRequster
was constructed by Fragment, lambda passed intoLiveData.observe
will still be registered, and observing LiveData won't stop when the Fragment diesThe text was updated successfully, but these errors were encountered: