tbruyelle / RxPermissions

Android runtime permissions powered by RxJava2

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

W/System.err: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

pradipawasthi opened this issue · comments

09-15 13:31:03.381 15829-15829/com.doubtnutapp W/System.err: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at androidx.fragment.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:2091)
at androidx.fragment.app.FragmentManagerImpl.ensureExecReady(FragmentManager.java:2229)
at androidx.fragment.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:2249)
at androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:648)
09-15 13:31:03.382 15829-15829/com.doubtnutapp W/System.err: at com.tbruyelle.rxpermissions2.RxPermissions.getRxPermissionsFragment(RxPermissions.java:77)
at com.tbruyelle.rxpermissions2.RxPermissions.access$000(RxPermissions.java:36)
at com.tbruyelle.rxpermissions2.RxPermissions$1.get(RxPermissions.java:61)
at com.tbruyelle.rxpermissions2.RxPermissions$1.get(RxPermissions.java:54)
at com.tbruyelle.rxpermissions2.RxPermissions.pending(RxPermissions.java:211)
at com.tbruyelle.rxpermissions2.RxPermissions.request(RxPermissions.java:200)
at com.tbruyelle.rxpermissions2.RxPermissions.access$100(RxPermissions.java:36)
at com.tbruyelle.rxpermissions2.RxPermissions$2.apply(RxPermissions.java:102)
at io.reactivex.Observable.compose(Observable.java:6283)
at com.tbruyelle.rxpermissions2.RxPermissions.request(RxPermissions.java:176)
at com.doubtnutapp.ui.splash.SplashActivity.requestPermission(SplashActivity.kt:143)
at com.doubtnutapp.ui.splash.SplashActivity$onStart$1.onInitFinished(SplashActivity.kt:131)
at io.branch.referral.ServerRequestRegisterInstall.onRequestSucceeded(ServerRequestRegisterInstall.java:106)
at io.branch.referral.Branch$BranchPostTask.onPostExecute(Branch.java:2937)
at io.branch.referral.Branch$BranchPostTask.onPostExecute(Branch.java:2799)
at android.os.AsyncTask.finish(AsyncTask.java:660)
at android.os.AsyncTask.-wrap1(AsyncTask.java)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:677)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:165)
at android.app.ActivityThread.main(ActivityThread.java:6365)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:883)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)

A lot of my app users have same problem and I don't know what to do...

commented

Maybe it's better to call commitAllowingStateLoss() than commitNow() .

问题解决了吗?我也遇到这个问题了

commented

I still use version 0.9.5 ,in this version, there is no this issue.

Thanks, I let't delay 200 millisecond, then no problem, if has problem I'm attempt your method!

我fork了一份解决了这个问题,比楼上的延时处理更好
https://github.com/YougaKing/RxPermissions.git

好像没有0.9.5 这个版本的吧

我fork了一份解决了这个问题,比楼上的延时处理更好
https://github.com/YougaKing/RxPermissions.git

你是处理的哪里

我fork了一份解决了这个问题,比楼上的延时处理更好
https://github.com/YougaKing/RxPermissions.git

你是处理的哪里

fragment 创建时机问题,java.lang.IllegalStateException

Same problem here

i have this problem too

i have problem too

A detailed description of the problem and what you have to do is here.
https://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html

In general, the best way to avoid the exception in these cases is to simply avoid committing transactions in asynchronous callback methods all together. Google engineers seem to agree with this belief as well. According to this post on the Android Developers group, the Android team considers the major shifts in UI that can result from committing FragmentTransactions from within asynchronous callback methods to be bad for the user experience.

we have to do:

  • either make a blocking call: blockingSubscribe()
  • either use: commitAllowingStateLoss()

@tim4dev disagree with your suggestions (but not with article). According to provided link

Use commitAllowingStateLoss() only as a last resort.

Good way of handling such situations will be dispose subscribtions to any org.reactivestreams.Publisher (e.g. Obsevable, Flowable etc) in Activity/Fragment onStop().
And if we speak about what is the best we could do with it I think in general we just don't need commit fragments transactions after onSaveInstanceState() was called.

We use a lot of Rx code in our projects and we've forgotten about described crashes since we started clear all related to screen subscribtions in onStop() (but we used to do it in onDestroy() untill SKD implementation of FragmentTransactions was changed).

@mrArtCore it's very good that you learned how to work with RxJava. But you can believe that none of us use calls after onSaveInstanceState, and yet the error appears. What exactly do you suggest?

@tim4dev Hey, I don't like your sarcasm.
First of all I tried to help. It appears that not all of users of this library quite familiar with Rx.
My suggestions:

  • give comprehensive example of your code or which is better link to sample project where this crash could be reproduced with more than 50% of success.
  • describe steps to reproduce
  • some additional info, that might be handy.

Show only stacktrace - is nothing. It's very hard understand what's going on if you will be look for problem solving without viewing from different perspectives.

This is an open source project, remember ? Nobody get paid for that fix. And if you are interested in this fix - give some help, please. Describe problem correctly!

Possible duplicate of #132 and #125

commented

so,will you change commitNow() to commitAllowingStateLoss()?
@tbruyelle

Same problem. It is hard to reproduce and seems like a random error.

Show us your code. Thats all. Oh, and stacktrace. And example project will be super helpful

@mrArtCore This is one of the crash logs from Crashlytics.
hasRightPermission is for getting whether a permission has been granted.

Fatal Exception: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
       at android.support.v4.app.FragmentManagerImpl.checkStateLoss(Unknown Source:10)
       at android.support.v4.app.FragmentManagerImpl.ensureExecReady(Unknown Source:51)
       at android.support.v4.app.FragmentManagerImpl.execSingleAction(Unknown Source:11)
       at android.support.v4.app.BackStackRecord.commitNow(Unknown Source:6)
       at com.tbruyelle.rxpermissions2.RxPermissions.getRxPermissionsFragment(Unknown Source:24)
       at com.tbruyelle.rxpermissions2.RxPermissions.access$000(Unknown Source)
       at com.tbruyelle.rxpermissions2.RxPermissions$1.get(Unknown Source:9)
       at com.tbruyelle.rxpermissions2.RxPermissions$1.get(Unknown Source)
       at com.tbruyelle.rxpermissions2.RxPermissions.isGranted(Unknown Source:8)
       at com.testapp.TestActivity.hasRightPermission(Unknown Source:9)
       at com.testapp.TestActivity.onCreateOptionsMenu(Unknown Source:37)
       at android.app.Activity.onCreatePanelMenu(Activity.java:3567)
       at android.support.v4.app.FragmentActivity.onCreatePanelMenu(Unknown Source:2)
       at android.support.v7.view.WindowCallbackWrapper.onCreatePanelMenu(Unknown Source:2)
       at android.support.v7.app.AppCompatDelegateImpl$AppCompatWindowCallback.onCreatePanelMenu(Unknown Source:8)
       at android.support.v7.view.WindowCallbackWrapper.onCreatePanelMenu(Unknown Source:2)
       at android.support.v7.app.ToolbarActionBar.populateOptionsMenu(Unknown Source:24)
       at android.support.v7.app.ToolbarActionBar$1.run(Unknown Source:2)
       at android.os.Handler.handleCallback(Handler.java:873)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:214)
       at android.app.ActivityThread.main(ActivityThread.java:6981)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)

Hi @stargt ! I see you have some testapp and just may be you are able to reproduce this crash ?
And what's more important that is code how you request permissions. Could you share it ?

I meet the same Exception

@wangjiangtao
Guys, how about to show code ? Did you check this
and this comments ?

Read carefully please, and if this is doesn't solve your problems, give us yout code example.

commented

我fork了一份解决了这个问题,比楼上的延时处理更好
https://github.com/YougaKing/RxPermissions.git

老哥,,,你的pull request 未被允许呀

我也是 不提供解决方案吗

0.10.2 still have this problem
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(SourceFile:2080)
at android.support.v4.app.FragmentManagerImpl.ensureExecReady(SourceFile:2219)
at android.support.v4.app.FragmentManagerImpl.execSingleAction(SourceFile:2239)
at android.support.v4.app.BackStackRecord.commitNow(SourceFile:648)
at com.tbruyelle.rxpermissions2.b.b(SourceFile:77)
at com.tbruyelle.rxpermissions2.b.a(SourceFile:36)
at com.tbruyelle.rxpermissions2.b$1.get(SourceFile:61)
at com.tbruyelle.rxpermissions2.b$1.get(SourceFile:54)
at com.tbruyelle.rxpermissions2.b.isGranted(SourceFile:308)
at **showPermission(SourceFile:25)
at **.onClick(SourceFile:332)
at android.view.View.performClick(View.java:6324)
at android.view.View$PerformClick.run(View.java:24977)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:192)
at android.app.ActivityThread.main(ActivityThread.java:6814)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:818)

This bug is also occasionally found on our side.

@zhuxiaohao @lkang08
Guys, if you provide code where such error could be reproduced (with "steps to reproduce" of course), I'll try to help. This crash affected many users, as I can see now... Guys, messages and stacktraces without code where bug could be represented worth nothing. Nobody want waste so much time here.
I've got idea why this crash appear (maybe it's about Permission emission without check for activeObservers) but I have no time to setup enviroment where crash could be reproduced.
Good luck!

I don't know what to do with rx methods and I can't create example that can reproduce this exception (I've spend whole evening in tryings and can't reproduce). But exception in rx methods will be emitted into downstream and easy to catch. More important that this exception can be thrown with isGranted methos which isn't rx method. I think, for such non-rx methods creation of fragment can be replaced with ContextCompat.checkSelfPermission methods.

@fAntel Your activity/fragment is not in 'right' state, I suppose. Maybe it happens when screen is rotated or something.
You can add check like lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) inside subscribe()method. Or something like this.
Play around. It's hard to suggest something useful while having no idea what is going on in your code.

@mrArtCore if we look at stack traces above we can see this line
com.tbruyelle.rxpermissions2.RxPermissions.getRxPermissionsFragment
It create fragment inside library code. Even on non-rx methods like isGranted. And I suggest to swap this with ContextCompat.checkSelfPermission call inside library code.
As workaround I've already swaped all RxPermissions.isGranted calls with ContextCompat.checkSelfPermission in my app because error in rx pipeline will be consumed at onError method in subscribe but non-rx call RxPermission.isGranted if called at main thread will lead to crash.

@fAntel Thanks for suggestion. Still trying to stick to the library. But don't understand why, for calling three functions, which already implemented in AppCompat.

Wow

在 activity 的oncreate的时候就先使用rxpermission 把RxPermissionsFragment 的实例初始化并与当前activity相绑定就行,因为在RxPermissions的getRxPermissionsFragment中会做判断,判断该RxPermissionsFragment是否被初始化

You can use try catch,able to handle some scenarios.

@mrArtCore Sorry for trouble you, but please check my case:
My steps is following:
Load API -> request RxPermission -> Crash with same log:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
        at androidx.fragment.app.FragmentManager.checkStateLoss(FragmentManager.java:1703)
        at androidx.fragment.app.FragmentManager.ensureExecReady(FragmentManager.java:1806)
        at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1826)
        at androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:297)
        at com.tbruyelle.rxpermissions3.RxPermissions.getRxPermissionsFragment(RxPermissions.java:78)
        at com.tbruyelle.rxpermissions3.RxPermissions.access$000(RxPermissions.java:37)
        at com.tbruyelle.rxpermissions3.RxPermissions$1.get(RxPermissions.java:62)
        at com.tbruyelle.rxpermissions3.RxPermissions$1.get(RxPermissions.java:55)
        at com.tbruyelle.rxpermissions3.RxPermissions.pending(RxPermissions.java:212)
        at com.tbruyelle.rxpermissions3.RxPermissions.request(RxPermissions.java:201)
        at com.tbruyelle.rxpermissions3.RxPermissions.access$100(RxPermissions.java:37)
        at com.tbruyelle.rxpermissions3.RxPermissions$4.apply(RxPermissions.java:156)
        at io.reactivex.rxjava3.core.Observable.compose(Observable.java:6765)
        at com.tbruyelle.rxpermissions3.RxPermissions.requestEachCombined(RxPermissions.java:194)

My problem is when loading API -> user move app to background -> RxPermission called on background -> so crash happened!

So what should I do? Should I check if app is background and wait until app resume, then call RxPermisson?

commented

Can not perform this action after onSaveInstanceState

com.tbruyelle.rxpermissions2.RxPermissions.getRxPermissionsFragment

commented

how to solve it?

commented

@mrArtCore Sorry for trouble you, but please check my case:
My steps is following:
Load API -> request RxPermission -> Crash with same log:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
        at androidx.fragment.app.FragmentManager.checkStateLoss(FragmentManager.java:1703)
        at androidx.fragment.app.FragmentManager.ensureExecReady(FragmentManager.java:1806)
        at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1826)
        at androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:297)
        at com.tbruyelle.rxpermissions3.RxPermissions.getRxPermissionsFragment(RxPermissions.java:78)
        at com.tbruyelle.rxpermissions3.RxPermissions.access$000(RxPermissions.java:37)
        at com.tbruyelle.rxpermissions3.RxPermissions$1.get(RxPermissions.java:62)
        at com.tbruyelle.rxpermissions3.RxPermissions$1.get(RxPermissions.java:55)
        at com.tbruyelle.rxpermissions3.RxPermissions.pending(RxPermissions.java:212)
        at com.tbruyelle.rxpermissions3.RxPermissions.request(RxPermissions.java:201)
        at com.tbruyelle.rxpermissions3.RxPermissions.access$100(RxPermissions.java:37)
        at com.tbruyelle.rxpermissions3.RxPermissions$4.apply(RxPermissions.java:156)
        at io.reactivex.rxjava3.core.Observable.compose(Observable.java:6765)
        at com.tbruyelle.rxpermissions3.RxPermissions.requestEachCombined(RxPermissions.java:194)

My problem is when loading API -> user move app to background -> RxPermission called on background -> so crash happened!

So what should I do? Should I check if app is background and wait until app resume, then call RxPermisson?

have you solved it?

RxPermissions Class constructor creates a fragment;
In order to commit the fragment transaction, the activity from which the fragment was supposed to be created must be in the foreground.
image

The onSaveInstanceState method is called right before the onStop method. If a fragment transaction is committed after onSaveInstanceState, Error Cannot perform this action will be thrown.

Solution:

  1. If you are using ComponentActivity or any activity that is inherited from ComponentActivity (ie. FragmentActiviy or AppCompatActivity), can use the getLifecycle method of the activity using androidx.lifecycle library.

if (this?.lifecycle?.currentState?.isAtLeast(Lifecycle.State.RESUMED) == true)
new RxPermissions(activity)

Alternatively, we can use a boolean to keep track of activity lifecycles if the androidx.lifecycle library is not added in your project!

  1. This library has to update the code in RxPermissions.getRxPermissionsFragment from commitNow() to commitAllowingStateLoss(). Understand the difference from here

Try unsubscribe from the stream whenever the state is saved -> onSaveInstanceState is called. I suggest you do it in fragment/activity#onStop() callback and you will be good to go.