WAI
Status Update
Comments
da...@gmail.com <da...@gmail.com> #2
added bugreport
am...@google.com <am...@google.com> #3
Hi,
I am not observing any crash on NDP3 on Nexus 5x even after following the steps provided. So please provide the video of the issue.
Screen Record of the Issue
Please capture screen record or video of the issue using following steps:
adb shell screenrecord /sdcard/video.mp4
Subsequently use following command to pull the recorded file:
adb pull /sdcard/video.mp4
Attach the file to this issue.
Note: Please upload the files to google drive and share the folder to android-bugreport@google.com, then share the link here.
Also mention the frequency of the issue.
I am not observing any crash on NDP3 on Nexus 5x even after following the steps provided. So please provide the video of the issue.
Screen Record of the Issue
Please capture screen record or video of the issue using following steps:
adb shell screenrecord /sdcard/video.mp4
Subsequently use following command to pull the recorded file:
adb pull /sdcard/video.mp4
Attach the file to this issue.
Note: Please upload the files to google drive and share the folder to android-bugreport@google.com, then share the link here.
Also mention the frequency of the issue.
da...@gmail.com <da...@gmail.com> #4
Here is the video. this occurs every time I go to the home screen from this search result.
Video:https://drive.google.com/file/d/0B-eHYVYyBpyjUjExemRVYTk5bXM/view?usp=sharing
APK:https://drive.google.com/open?id=0B-eHYVYyBpyjQmQ2UnpacDVFVkU
This only occurs on a build of my app that has a compileSdkVersion / targetSdkVersion of N . Does not affect current production APK that targets Marshmallow
Video:
APK:
This only occurs on a build of my app that has a compileSdkVersion / targetSdkVersion of N . Does not affect current production APK that targets Marshmallow
am...@google.com <am...@google.com> #5
Hi,
We have passed this defect on to the development team and will update this issue with more information as it becomes available.
Thanks
We have passed this defect on to the development team and will update this issue with more information as it becomes available.
Thanks
k....@gmail.com <k....@gmail.com> #6
[Comment deleted]
k....@gmail.com <k....@gmail.com> #7
Looks like I have the similar issue on targetSdkVersion 24 and in my case it relates to huge saved state.
Moreover, looks like on compile/targetSdkVersion = 23 we have only internal warning about large size of saved state, but nothing is crashed:
E/ActivityThread: App sent too much data in instance state, so it was ignored
android.os.TransactionTooLargeException: data parcel size 713856 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3604)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3729)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6044)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
But on compile/targetSdkVersion = 24 we have real RuntimeException crash in this case:
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 713860 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3737)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6044)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Caused by: android.os.TransactionTooLargeException: data parcel size 713860 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3604)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3729)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6044)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Moreover, looks like on compile/targetSdkVersion = 23 we have only internal warning about large size of saved state, but nothing is crashed:
E/ActivityThread: App sent too much data in instance state, so it was ignored
android.os.TransactionTooLargeException: data parcel size 713856 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3604)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3729)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6044)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
But on compile/targetSdkVersion = 24 we have real RuntimeException crash in this case:
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 713860 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3737)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6044)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Caused by: android.os.TransactionTooLargeException: data parcel size 713860 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3604)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3729)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6044)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
st...@gmail.com <st...@gmail.com> #8
[Comment deleted]
st...@gmail.com <st...@gmail.com> #9
[Comment deleted]
ha...@gmail.com <ha...@gmail.com> #10
Observe same issue with Nexus 9 and Nexus 5X running build number NPD90G, during Activity.onSaveInstanceState(), with reported parcel size as low as ~600KB.
Other devices running Android N or 7 also suffer same issue, please see attached screenshot for device statistics.
Other devices running Android N or 7 also suffer same issue, please see attached screenshot for device statistics.
de...@idealo.de <de...@idealo.de> #11
By the way: this was mentioned as a behavior change for Android N: https://developer.android.com/preview/behavior-changes.html
Quote:
"Many platform APIs have now started checking for large payloads being sent across Binder transactions, and the system now rethrows TransactionTooLargeExceptions as RuntimeExceptions, instead of silently logging or suppressing them. One common example is storing too much data in Activity.onSaveInstanceState(), which causes ActivityThread.StopInfo to throw a RuntimeException when your app targets Android N."
Quote:
"Many platform APIs have now started checking for large payloads being sent across Binder transactions, and the system now rethrows TransactionTooLargeExceptions as RuntimeExceptions, instead of silently logging or suppressing them. One common example is storing too much data in Activity.onSaveInstanceState(), which causes ActivityThread.StopInfo to throw a RuntimeException when your app targets Android N."
st...@gmail.com <st...@gmail.com> #12
[Comment deleted]
st...@gmail.com <st...@gmail.com> #13
[Comment deleted]
st...@gmail.com <st...@gmail.com> #14
I don't know why but removing
fragmentTransaction.addToBackStack(null);
fixed the problem for me.
Hope can help someone else
fragmentTransaction.addToBackStack(null);
fixed the problem for me.
Hope can help someone else
am...@google.com <am...@google.com> #15
Since this is an app bug , we have reached out to the app developer.
st...@gmail.com <st...@gmail.com> #16
[Comment deleted]
st...@gmail.com <st...@gmail.com> #17
[Comment deleted]
st...@gmail.com <st...@gmail.com> #18
amruthav
i have not clear if issue has been fixed and what you mean with it's an app bug.
This is a change in Android N behaviour causing apps to crash, not an issue related to a specific app.
i have not clear if issue has been fixed and what you mean with it's an app bug.
This is a change in Android N behaviour causing apps to crash, not an issue related to a specific app.
[Deleted User] <[Deleted User]> #19
My application is currently crashing because exactly same reason. What is the recommended way to save large amount of data so it can be accessed again when fragment/activity is restored?
[Deleted User] <[Deleted User]> #20
FWIW I kind of band-aid solution that does following that stop the program from crashing on
@Override
public void onSaveInstanceState(Bundle stateBundle) {
int osVersion = android.os.Build.VERSION.SDK_INT;
if ( osVersion < Build.VERSION_CODES.N) {
....
super.onSaveInstanceState(stateBundle);
}
}
FWIW I am running version 7.0 Build Number NPD90G on Galaxy Nexus. I can point to APK in case anyone wants to analyze issue/suggest fix.
@Override
public void onSaveInstanceState(Bundle stateBundle) {
int osVersion = android.os.Build.VERSION.SDK_INT;
if ( osVersion < Build.VERSION_CODES.N) {
....
super.onSaveInstanceState(stateBundle);
}
}
FWIW I am running version 7.0 Build Number NPD90G on Galaxy Nexus. I can point to APK in case anyone wants to analyze issue/suggest fix.
am...@google.com <am...@google.com> #21
Development team has decided to make it as WAI due to below reason
Target is aware of this issue and is holding off on targeting 24+ until they devise good solutions for this and a few other issues. Namely, they're coming up somewhat quickly to Q4, and won't be targeting 24+ until after that's over.
As such, resolving as WAI.
Target is aware of this issue and is holding off on targeting 24+ until they devise good solutions for this and a few other issues. Namely, they're coming up somewhat quickly to Q4, and won't be targeting 24+ until after that's over.
As such, resolving as WAI.
[Deleted User] <[Deleted User]> #22
Not sure what is meant by 'Target' in above response? So if I want to release this app target it for google's 'N' platform which will be available end of Aug, I am on my own need to come up with my own solution?
st...@gmail.com <st...@gmail.com> #23
I really can't understand status WAI.
If it's working as intended i expect there's nothing to fix.
If you are working on it ..there's an issue.
Targeting 23 is just a workaround already suggested in #6
If it's working as intended i expect there's nothing to fix.
If you are working on it ..there's an issue.
Targeting 23 is just a workaround already suggested in #6
[Deleted User] <[Deleted User]> #24
We are seeing this as well.
While this may be "working as intended", this is quite a poorly executed change to the platform that is going to cause many apps to crash with little explanation or recourse. Our app is crashing consistently on devices that are receiving the update to N.
Such a change would seem to warrant more than a bullet point in the behavior changes description.
It would be nice to see a blog or something explaining the rational for this change, the payload size the system supports for saving state, and a suggested alternative for developers that want to properly save and restore state when dealing with large data sets.
We're reverting to targeting API 23 until such information is available.
@#23: "Target" literally refers to "Target", the department store company, whose app was the basis for the initial report. (see comment that "Target has stopped" and see video showing the Target shopping app.
@amruthav: just because Target has opted to punt on this issue does not mean it is resolved. Will there be an update to this issue, or some documentation, or some guidance on how to handle this scenario?
Thanks.
While this may be "working as intended", this is quite a poorly executed change to the platform that is going to cause many apps to crash with little explanation or recourse. Our app is crashing consistently on devices that are receiving the update to N.
Such a change would seem to warrant more than a bullet point in the behavior changes description.
It would be nice to see a blog or something explaining the rational for this change, the payload size the system supports for saving state, and a suggested alternative for developers that want to properly save and restore state when dealing with large data sets.
We're reverting to targeting API 23 until such information is available.
@#23: "Target" literally refers to "Target", the department store company, whose app was the basis for the initial report. (see comment that "Target has stopped" and see video showing the Target shopping app.
@amruthav: just because Target has opted to punt on this issue does not mean it is resolved. Will there be an update to this issue, or some documentation, or some guidance on how to handle this scenario?
Thanks.
[Deleted User] <[Deleted User]> #25
I am facing the same issue, will it be fixed or is there any workaround to handle this?
su...@socialnmobile.com <su...@socialnmobile.com> #26
If this exception is work as intended, I also need to fix my app. To fix my app, I want to know more information from the stack trace. How about to include activity name or fragment name that cause this problem in exception message?
ru...@gmail.com <ru...@gmail.com> #27
I have also started receiving crashes from users with Android N. This is not working as intended. We are unable to identify the location of the crash by just looking at the stack trace from user crash reports. This issue alone is a serious problem.
I believe many others developers have their apps crashing but they still don't know it. I only came to this because I have Fabric integrated in the app and I noticed that 100% of the crashes were coming from Android 7. And then, I was able to reproduce the error by navigating in the app in an Android 7 emulator (because the stack trace doesn't say were the crash is occurring).
I believe many others developers have their apps crashing but they still don't know it. I only came to this because I have Fabric integrated in the app and I noticed that 100% of the crashes were coming from Android 7. And then, I was able to reproduce the error by navigating in the app in an Android 7 emulator (because the stack trace doesn't say were the crash is occurring).
[Deleted User] <[Deleted User]> #28
I too am encountering this issue on Android 7. We encountered this problem while adding multi-window support to our app. It happens due to saving a larger chunk of data (but still not too large) in the instance state (in onSaveInstanceState)
to...@gmail.com <to...@gmail.com> #29
Hi, can I be notified of updates on this issue as well please?
I only get this issue on targetSdkVersion 24, not 23 and below. It seems to be trigged by our main base activity, from onSaveInstanceState. Trying to override the onSaveInstanceState in the fragment, and do nothing for OS N, doesn't get called before the crash.
I only get this issue on targetSdkVersion 24, not 23 and below. It seems to be trigged by our main base activity, from onSaveInstanceState. Trying to override the onSaveInstanceState in the fragment, and do nothing for OS N, doesn't get called before the crash.
su...@gmail.com <su...@gmail.com> #30
Any update on this issue? We are starting to receive production crashes and all of them coming from Android N. This is getting serious day by day!!
zh...@gmail.com <zh...@gmail.com> #31
You need to fix your state persistence to not persist so much data into the Bundle. This was always an error in your application, you just never noticed because it was logged as a warning.
[Deleted User] <[Deleted User]> #32
Seems pretty obvious that "You need to fix your state persistence to not persist so much data into the Bundle." Would you be able to tell us what defines "so much data"?
TL;DR:
We need some officially recommended / documented practices to handle state correctly to avoid crashing on N. Specifically:
- What's the recommended minimum state size that won't crash your app?
- What's the best practice for determining this size in your parcel?
- What's the recommendation for saving state if you can't reasonably reduce your state size below this minimum?
The issue at hand is that this warning (which is easy to miss in LogCat spam) was promoted to a hard crash with nothing more than a bullet point on the release notes.
https://developer.android.com/about/versions/nougat/android-7.0-changes.html#other
"Many platform APIs have now started checking for large payloads being sent across Binder transactions, and the system now rethrows TransactionTooLargeExceptions as RuntimeExceptions, instead of silently logging or suppressing them. One common example is storing too much data in Activity.onSaveInstanceState(), which causes ActivityThread.StopInfo to throw a RuntimeException when your app targets Android 7.0."
The docs I see for this method are:
https://developer.android.com/training/basics/activity-lifecycle/recreating.html#SaveState
https://developer.android.com/reference/android/app/Activity.html#onSaveInstanceState(android.os.Bundle)
I don't see where any of the documentation warns about the potential to crash with "too much" data, much less what constitutes "too much".
Here's a comment from Dianne Hackborn on the issue:
http://blog.sqisland.com/2016/09/transactiontoolargeexception-crashes-nougat.html?showComment=1474217554727#c1100089308063228299
"So I would recommend keeping the saved state well less than 100K, and really less than 50K, and in most cases much less than even that."
So, what? Shoot for < 50K? But we could potentially get away with 50K - 100K? So maybe < 100K? Then what? Wait for the app to crash to find out if that was "too much"? Then trim some more and try again and wait for the app to crash again?
How are we supposed to target N and handle saving / restoring state with confidence when this method can, at any time, crash the entire app due to some arbitrary and unspecified amount of data that is now considered "too much"?
TL;DR:
We need some officially recommended / documented practices to handle state correctly to avoid crashing on N. Specifically:
- What's the recommended minimum state size that won't crash your app?
- What's the best practice for determining this size in your parcel?
- What's the recommendation for saving state if you can't reasonably reduce your state size below this minimum?
The issue at hand is that this warning (which is easy to miss in LogCat spam) was promoted to a hard crash with nothing more than a bullet point on the release notes.
"Many platform APIs have now started checking for large payloads being sent across Binder transactions, and the system now rethrows TransactionTooLargeExceptions as RuntimeExceptions, instead of silently logging or suppressing them. One common example is storing too much data in Activity.onSaveInstanceState(), which causes ActivityThread.StopInfo to throw a RuntimeException when your app targets Android 7.0."
The docs I see for this method are:
I don't see where any of the documentation warns about the potential to crash with "too much" data, much less what constitutes "too much".
Here's a comment from Dianne Hackborn on the issue:
"So I would recommend keeping the saved state well less than 100K, and really less than 50K, and in most cases much less than even that."
So, what? Shoot for < 50K? But we could potentially get away with 50K - 100K? So maybe < 100K? Then what? Wait for the app to crash to find out if that was "too much"? Then trim some more and try again and wait for the app to crash again?
How are we supposed to target N and handle saving / restoring state with confidence when this method can, at any time, crash the entire app due to some arbitrary and unspecified amount of data that is now considered "too much"?
st...@gmail.com <st...@gmail.com> #33
[Comment deleted]
da...@gmail.com <da...@gmail.com> #34
I believe 512kb is the threshold
st...@gmail.com <st...@gmail.com> #35
How much is too much? According to official docs, size limit is 1 Mb
https://developer.android.com/reference/android/os/TransactionTooLargeException.html
What is not clear (at least for me) is if Binder transaction buffer is shared between processes.
I'm not saving 1mb but having the problem too.
So i guess all paused app are saving data to the same buffer..but maybe i'm wrong. So how much is too much for your app may depends on other apps too.
What is not clear (at least for me) is if Binder transaction buffer is shared between processes.
I'm not saving 1mb but having the problem too.
So i guess all paused app are saving data to the same buffer..but maybe i'm wrong. So how much is too much for your app may depends on other apps too.
[Deleted User] <[Deleted User]> #36
From that doc, the 1MB is "is shared by all transactions in progress for the process. Consequently this exception can be thrown when there are many transactions in progress even when most of the individual transactions are of moderate size."
Which means any call to save instance state can push you over the limit, even if it's tiny. So, again, how is one supposed to know they're potentially breaching that limit?
Which means any call to save instance state can push you over the limit, even if it's tiny. So, again, how is one supposed to know they're potentially breaching that limit?
ru...@gmail.com <ru...@gmail.com> #37
This is more revealing than any other official documentation:
https://www.neotechsoftware.com/blog/android-intent-size-limit
Stating that the limit for the transaction is 1 MB is simply wrong. We can reproduce and prove that it is not the case.
And please, when there are quite a few people stating in this thread that the app crashes with a bundle size of around 600000 bytes, do not justify the behavior of the crash stating that the limit is 1 MB and we are the ones who are doing things wrong. It's dishonest at least.
With the introduction of this "feature" we cannot rely on a saved state. Specially when our data is dynamic and not fixed in size. From now on, I have to look at the saved state with another mindset. Just save some view data and maybe some booleans. Forget about saving something that you just fetched from the network. We have to cache everything on DB or file and retrieve that on resuming. Which, for any new app under development is no big deal, but for any developer that has legacy apps under his wings, it's...
Stating that the limit for the transaction is 1 MB is simply wrong. We can reproduce and prove that it is not the case.
And please, when there are quite a few people stating in this thread that the app crashes with a bundle size of around 600000 bytes, do not justify the behavior of the crash stating that the limit is 1 MB and we are the ones who are doing things wrong. It's dishonest at least.
With the introduction of this "feature" we cannot rely on a saved state. Specially when our data is dynamic and not fixed in size. From now on, I have to look at the saved state with another mindset. Just save some view data and maybe some booleans. Forget about saving something that you just fetched from the network. We have to cache everything on DB or file and retrieve that on resuming. Which, for any new app under development is no big deal, but for any developer that has legacy apps under his wings, it's...
ta...@gmail.com <ta...@gmail.com> #38
Anyone using WebView, watch out for WebView.saveState(). You should probably avoid calling this method on Android 7.0.
My crash logs narrow down the crash to a Fragment containing a WebView. (By manually tagging which Fragment was last resumed. Like others have said, stack trace is not helpful.)
I am calling WebView.saveState() in my onSaveInstanceState. saveState() delegates to WebViewProvider. I cannot inspect WebViewProvider to see what exactly it is putting into the Bundle, since it is a system API stub.
Through testing, apparently the WebView.saveState() method adds a byte array of several kilobytes per page in the WebView history stack. The size seems to vary depending on the page content. One link resulted in 8 KB added to the Bundle; 10 links totaled 140 KB; I randomly clicked around a news site for a few minutes, and the byte array seemed to top off around 400 KB. I guess the history stack truncates after a certain length.
I tested on a different, image-heavy site, and after clicking through several pages of high quality photos, the Bundle easily surpassed 1000 KB, and triggered the TransactionTooLargeException.
My crash logs narrow down the crash to a Fragment containing a WebView. (By manually tagging which Fragment was last resumed. Like others have said, stack trace is not helpful.)
I am calling WebView.saveState() in my onSaveInstanceState. saveState() delegates to WebViewProvider. I cannot inspect WebViewProvider to see what exactly it is putting into the Bundle, since it is a system API stub.
Through testing, apparently the WebView.saveState() method adds a byte array of several kilobytes per page in the WebView history stack. The size seems to vary depending on the page content. One link resulted in 8 KB added to the Bundle; 10 links totaled 140 KB; I randomly clicked around a news site for a few minutes, and the byte array seemed to top off around 400 KB. I guess the history stack truncates after a certain length.
I tested on a different, image-heavy site, and after clicking through several pages of high quality photos, the Bundle easily surpassed 1000 KB, and triggered the TransactionTooLargeException.
lo...@gmail.com <lo...@gmail.com> #39
Hi all, In this week I had a lot of problems with this error. For my was a terrible problem :-( I included 8 photos (no so big) in cache. And for this reason crash my app. I solved put in a local Hash Map, the user photos. It's no so good, but for me it works.
ki...@gmail.com <ki...@gmail.com> #40
This makes the "saveInstanceState" totally useless. The document says that we should save the state so the user won't lose there progress. But now it's like, whatever, you're gonna lose something anyway.
I don't think saving the content into the database is a good choice. It costs too much time and battery life. Android 7.0 devices all have an 2G up RAM. This limit doesn't make sense. And this behavior change does not describe in the traditional-chinese version on this page:https://developer.android.com/preview/behavior-changes.html .
So, what's the best way to fix this problem? It's a huge change, it can't be no any document about how to implement.
If save the instance state into a file or database is what we should do, instead of throwing exception, why don't you just add this storing feature as a default behavior of the large data?
I don't think saving the content into the database is a good choice. It costs too much time and battery life. Android 7.0 devices all have an 2G up RAM. This limit doesn't make sense. And this behavior change does not describe in the traditional-chinese version on this page:
So, what's the best way to fix this problem? It's a huge change, it can't be no any document about how to implement.
If save the instance state into a file or database is what we should do, instead of throwing exception, why don't you just add this storing feature as a default behavior of the large data?
[Deleted User] <[Deleted User]> #41
Hand waving this away as "Working as intended" is unacceptable from the point of view of anyone who has anything other than a brand new app or a very trivial one.
This is a breaking change, and such deserved much more emphasis in the change logs than it actually got.
But, more importantly, if your aim is to treat your developers with any degree of decency, you really should have, well in advance, laid out some viable alternatives for saving transient state which is nevertheless computationally or time-expensive, but doesn't warrant the hassle of dedicated DB or other file system persistence in the client application - this is what onSaveInstanceState was used for, and this is what you've made it largely useless for with this change.
If this just stands, what you'll accomplish is that a lot of developers, at least for the time being, out of pressure, will opt to stop saving a lot of state, rather than refactoring a large codebase to use some home-cooked alternative in place of onSaveInstanceState - the end result will be a poorer user experience which reflects badly on the entire platform.
So to just say that it's "Working as intended", must either be a cruel joke or gross mismanagement of your developer relations on this issue.
I'm leaning towards the latter, but you really need to address it with something much more substantial than vague mentions of the size limits, and you need to do it soon, while the flood gates haven't fully opened yet. It looks like you're underestimating just how badly and how many apps out there could be affected by this.
Ideally, you give us at least the following:
- Why did you make this change, and how do we or the user benefit from it?
- Official statement and documentation on the relevant methods about the size limit.
- Possible alternatives that don't take a man-week of refactoring and testing on a reasonably large app.
This whole thing is giving me ugly flashbacks to the arbitrary 64K dex method limit. But that one was at least conceived at a time when it wasn't a problem and took years until it became one, and even then it was a compiletime issue, not a runtime crash.
This is a breaking change, and such deserved much more emphasis in the change logs than it actually got.
But, more importantly, if your aim is to treat your developers with any degree of decency, you really should have, well in advance, laid out some viable alternatives for saving transient state which is nevertheless computationally or time-expensive, but doesn't warrant the hassle of dedicated DB or other file system persistence in the client application - this is what onSaveInstanceState was used for, and this is what you've made it largely useless for with this change.
If this just stands, what you'll accomplish is that a lot of developers, at least for the time being, out of pressure, will opt to stop saving a lot of state, rather than refactoring a large codebase to use some home-cooked alternative in place of onSaveInstanceState - the end result will be a poorer user experience which reflects badly on the entire platform.
So to just say that it's "Working as intended", must either be a cruel joke or gross mismanagement of your developer relations on this issue.
I'm leaning towards the latter, but you really need to address it with something much more substantial than vague mentions of the size limits, and you need to do it soon, while the flood gates haven't fully opened yet. It looks like you're underestimating just how badly and how many apps out there could be affected by this.
Ideally, you give us at least the following:
- Why did you make this change, and how do we or the user benefit from it?
- Official statement and documentation on the relevant methods about the size limit.
- Possible alternatives that don't take a man-week of refactoring and testing on a reasonably large app.
This whole thing is giving me ugly flashbacks to the arbitrary 64K dex method limit. But that one was at least conceived at a time when it wasn't a problem and took years until it became one, and even then it was a compiletime issue, not a runtime crash.
[Deleted User] <[Deleted User]> #42
[Comment deleted]
[Deleted User] <[Deleted User]> #43
[Comment deleted]
[Deleted User] <[Deleted User]> #44
App affected by this Android N system behavior change. Crash seeing on Android N phone only.
Revert to sdk 23 and target 23 solves the problem.
But, Google Android Team, where is your guideline on how to defend against the crash? In our case, a view pager with 6 or 7 fragments crashes whenever I press the recent tasks button, provided that I turned on Don't Keep Activities developer option.
Revert to sdk 23 and target 23 solves the problem.
But, Google Android Team, where is your guideline on how to defend against the crash? In our case, a view pager with 6 or 7 fragments crashes whenever I press the recent tasks button, provided that I turned on Don't Keep Activities developer option.
ra...@gmail.com <ra...@gmail.com> #45
I saw the same exception only on nougat. But i never override onSavedInstacneState in my activity. But there are lot of views and there are few third party libs. I could not get to the bottom of the issue. So to check i decided to override @Override
protected void onSaveInstanceState(Bundle outState) {
// below line to be commented to prevent crash on nougat.
//http://blog.sqisland.com/2016/09/transactiontoolargeexception-crashes-nougat.html
//
//super.onSaveInstanceState(outState);
}
Guess what i don't see the crash. It was really hard cause it was not my app but i was hired to fix bugs. I have read all the comments and i am not sure where the problem lies. third party libs or too many views in a single screen...
protected void onSaveInstanceState(Bundle outState) {
// below line to be commented to prevent crash on nougat.
//
//
//super.onSaveInstanceState(outState);
}
Guess what i don't see the crash. It was really hard cause it was not my app but i was hired to fix bugs. I have read all the comments and i am not sure where the problem lies. third party libs or too many views in a single screen...
ni...@gmail.com <ni...@gmail.com> #46
I am facing the same issue in my Google Pixel XL Android N device. But I have only one activity and its portrait locked. So I am not keeping the onSavedInstanceState(). My activity is loading 3 fragments and keeping fragment back stack. Any solution for this issue?.
Please check the log
Fatal Exception: java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 3378232 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3755)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6088)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by android.os.TransactionTooLargeException: data parcel size 3378232 bytes
at android.os.BinderProxy.transactNative(Binder.java)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3628)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3747)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6088)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Please check the log
Fatal Exception: java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 3378232 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3755)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6088)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by android.os.TransactionTooLargeException: data parcel size 3378232 bytes
at android.os.BinderProxy.transactNative(Binder.java)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3628)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3747)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6088)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
ea...@gmail.com <ea...@gmail.com> #47
External library can be a reason of it. For example, FacebookSDK3 has PictureProfileView which stores the whole Bitmap in its onSaveInstanceState().
ni...@gmail.com <ni...@gmail.com> #48
I am using Glide for showing URL images.Will this cause any issue?
[Deleted User] <[Deleted User]> #49
My app crashes with TransactionTooLargeException due to a WebView somewhere (an incentive to go full native I guess?).
I worked around it by saving the WebView's state not to the provided Bundle in onSaveInstanceState() but to a file.
I.e. (minus the error handling):
Bundle tmp = new Bundle();
webView.saveState(tmp);
byte[] state = tmp.getByteArray("WEBVIEW_CHROMIUM_STATE");
File stateFile = new File(getCacheDir(), "filename");
FileUtils.writeByteArrayToFile(stateFile, state);
I worked around it by saving the WebView's state not to the provided Bundle in onSaveInstanceState() but to a file.
I.e. (minus the error handling):
Bundle tmp = new Bundle();
webView.saveState(tmp);
byte[] state = tmp.getByteArray("WEBVIEW_CHROMIUM_STATE");
File stateFile = new File(getCacheDir(), "filename");
FileUtils.writeByteArrayToFile(stateFile, state);
an...@gmail.com <an...@gmail.com> #50
@amruthav
What means 'WAI' ?
What means 'WAI' ?
[Deleted User] <[Deleted User]> #51
@anruf0
It means "Working As Intended". Or, by extension, it means you, and the rest of us are s**t out of luck, until someone in the Android dev team decides to chime in again.
It means "Working As Intended". Or, by extension, it means you, and the rest of us are s**t out of luck, until someone in the Android dev team decides to chime in again.
ni...@gmail.com <ni...@gmail.com> #52
I face the similar issue. I don't know this scenario is same, but I fix it
in the following way. Please check the scenario and solution.
Scenario: I got a weird bug from the customer in the Google Nexus P
device(7 OS) as my application will crash after 4 hours of working. Later I
identify that it's throwing the similar exception.
Solution: I found that this is happening in my application, because of
keeping the back stack of fragments. In my case, 4 fragments are added to
the back stack repeatedly with the help of an auto screen movement
animation. So I override the onBackstackChangeListener as mention below.
@Override
public void onBackStackChanged() {
try {
int count = mFragmentMngr.getBackStackEntryCount();
if (count > 0) {
if (count > 30) {
mFragmentMngr.popBackStack(1,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
count = mFragmentMngr.getBackStackEntryCount();
}
FragmentManager.BackStackEntry entry =
mFragmentMngr.getBackStackEntryAt(count - 1);
mCurrentlyLoadedFragment = Integer.parseInt(entry.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
I hope this may help your issue.
The contents of this e-mail message and any attachments are confidential
and are intended solely for the addressee. The information may also be
legally privileged. This transmission is sent in trust, for the sole
purpose of delivery to the intended recipient. If you have received this
transmission in error, any use, reproduction or dissemination of this
transmission is strictly prohibited. If you are not the intended recipient,
please immediately notify the sender by reply e-mail or phone and delete this
message and its attachments, if any.
in the following way. Please check the scenario and solution.
Scenario: I got a weird bug from the customer in the Google Nexus P
device(7 OS) as my application will crash after 4 hours of working. Later I
identify that it's throwing the similar exception.
Solution: I found that this is happening in my application, because of
keeping the back stack of fragments. In my case, 4 fragments are added to
the back stack repeatedly with the help of an auto screen movement
animation. So I override the onBackstackChangeListener as mention below.
@Override
public void onBackStackChanged() {
try {
int count = mFragmentMngr.getBackStackEntryCount();
if (count > 0) {
if (count > 30) {
mFragmentMngr.popBackStack(1,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
count = mFragmentMngr.getBackStackEntryCount();
}
FragmentManager.BackStackEntry entry =
mFragmentMngr.getBackStackEntryAt(count - 1);
mCurrentlyLoadedFragment = Integer.parseInt(entry.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
I hope this may help your issue.
The contents of this e-mail message and any attachments are confidential
and are intended solely for the addressee. The information may also be
legally privileged. This transmission is sent in trust, for the sole
purpose of delivery to the intended recipient. If you have received this
transmission in error, any use, reproduction or dissemination of this
transmission is strictly prohibited. If you are not the intended recipient,
please immediately notify the sender by reply e-mail or phone and delete this
message and its attachments, if any.
jn...@virtualproperties.com <jn...@virtualproperties.com> #53
Rather than persisting data in a file or local sqlitedb I've worked around this issue by pushing the data into an activity specific singleton in onSaveInstanceState and pull it out of the activity specific singleton in onRestoreInstanceState. See attached sample application. Can someone comment as to whether or not using a signleton to persist data in this manner is bad practice?
[Deleted User] <[Deleted User]> #54
@jnelle - you might be able to get away with this in a simple app, but I think you'll run into issues quickly.
1 - your current sample has one blob of data for one activity. As soon as you have two instances of the same activity you'll overwrite data and / or get the wrong data in the wrong activity as the user navigates through them. You'd have to add more logic to track which blob of data is associated with which instance of a previous activity, which will get complicated very quickly.
2 - storing data statically in your app means you use up your own app's memory, increasing the likelihood that the system will kill your entire app to reclaim that memory, thus invalidating all the work you did to try to save that state in the first place.
1 - your current sample has one blob of data for one activity. As soon as you have two instances of the same activity you'll overwrite data and / or get the wrong data in the wrong activity as the user navigates through them. You'd have to add more logic to track which blob of data is associated with which instance of a previous activity, which will get complicated very quickly.
2 - storing data statically in your app means you use up your own app's memory, increasing the likelihood that the system will kill your entire app to reclaim that memory, thus invalidating all the work you did to try to save that state in the first place.
jn...@virtualproperties.com <jn...@virtualproperties.com> #55
@l...@reverb.com
Thanks for your comments. While your comment #1 isn't as concerning in our situation (because the same challenge exists if writing to file or sqlitedb), #2 is and so I'll consider switching over to writing to file or sqlitedb. It would be nice to know what the best practice for persisting large amounts of data in a bundle is however. If you or anyone else could provide reference it would be helpful.
Thanks
Thanks for your comments. While your
Thanks
ru...@gmail.com <ru...@gmail.com> #56
I tried to persist the data in Realm, and actually build a small InstanceStateHelper for that. It seemed to work in tests, but while in production I started to get very concerning crashes. About 200 to 300 users per week in 500000 were crashing hard. I guess they were the most active users (which makes the problem worse).
It seemed that the DB grew too much in size in those situations and the dreadful OutOfMemory errors started to appear.
The problem is the DB clean up. If the app is very big, and there are many instances of Fragments with saved states, the management of the DB can be troublesome during runtime.
I gave up that idea, went back to target Android 6, and declared the app dead to Android 7 and above.
It seemed that the DB grew too much in size in those situations and the dreadful OutOfMemory errors started to appear.
The problem is the DB clean up. If the app is very big, and there are many instances of Fragments with saved states, the management of the DB can be troublesome during runtime.
I gave up that idea, went back to target Android 6, and declared the app dead to Android 7 and above.
ma...@gmail.com <ma...@gmail.com> #57
Furthermore persisting data as a static singleton instance means when your
app is backgrounded and destroyed due to low memory the data will not be
there and likely your app will crash.
app is backgrounded and destroyed due to low memory the data will not be
there and likely your app will crash.
wh...@gmail.com <wh...@gmail.com> #58
I think this issue is really troublesome for me.
I use a lot of fragment in single activity, this issue sometimes occur, sometimes not.
Tips from stef.ba...@gmail.com and nithinji...@gmail.com lead me to Fragment BackStackEntry. Removing any function of it on my OnBackPressed solve my issue. But Now I need to find a way to track that BackStackEntry.
But the weird thing is, this issue happen to me when I open new activity from activity which has a lot of fragments.
I think this is system bug.
I use a lot of fragment in single activity, this issue sometimes occur, sometimes not.
Tips from stef.ba...@gmail.com and nithinji...@gmail.com lead me to Fragment BackStackEntry. Removing any function of it on my OnBackPressed solve my issue. But Now I need to find a way to track that BackStackEntry.
But the weird thing is, this issue happen to me when I open new activity from activity which has a lot of fragments.
I think this is system bug.
[Deleted User] <[Deleted User]> #59
Is there any info regarding a work around to this "bug"? My app is getting this crash as well
wh...@gmail.com <wh...@gmail.com> #60
I found my real culprit. It's a dynamic size String object in one of my fragment's onSaveInstanceState, sometimes it produce a bit more than 1mb.
Fortunately it can be recreated again, if network is available. I may save it to storage if necessary.
The problem with this new "restriction" is to find the object. Android Studio doesn't give understandable error log, it seems refering to the system (It always refers to Handler).
Fortunately it can be recreated again, if network is available. I may save it to storage if necessary.
The problem with this new "restriction" is to find the object. Android Studio doesn't give understandable error log, it seems refering to the system (It always refers to Handler).
[Deleted User] <[Deleted User]> #61
[Comment deleted]
[Deleted User] <[Deleted User]> #62
@wherethe... You found a culprit for this one particular case, but as your
app gets bigger and you save more and more state in an effort to provide a
smoother user experience, with this new change you'll always have to be
looking over your shoulder for this issue to come back and bite you in the
ass.
I'm working on a drop-in library in my spare time, to avoid this issue for
good, and will post back here with either a github link for you guys to
contribute to, or with questions if I hit some roadblock. In the meantime,
if anyone else has some solution already, or is working on something
similar, please let me know.
app gets bigger and you save more and more state in an effort to provide a
smoother user experience, with this new change you'll always have to be
looking over your shoulder for this issue to come back and bite you in the
ass.
I'm working on a drop-in library in my spare time, to avoid this issue for
good, and will post back here with either a github link for you guys to
contribute to, or with questions if I hit some roadblock. In the meantime,
if anyone else has some solution already, or is working on something
similar, please let me know.
ts...@gmail.com <ts...@gmail.com> #63
I'm struggling with this issue for last 3 days. It's crashing when I'm trying to send a simple object from Activity A to Activity B. The size of the object can reach hardly 1KB which is not really comparable with the limit (1MB) stated in developer.android.com .
As many developers are facing this issue and still no solution come out I hope google will come out with a straightforward solution to handle this issue or if it's really OS level problem google should fix the bug from android N ASAP.
As many developers are facing this issue and still no solution come out I hope google will come out with a straightforward solution to handle this issue or if it's really OS level problem google should fix the bug from android N ASAP.
ke...@gmail.com <ke...@gmail.com> #64
My workaround, really really bad:
1. Activity: onSaveInstanceState(Bundle outState):
super.onSaveInstanceState(outState); // it'll collect saved state from fragments and views
if (os >= Android 7) {
Bundle bundle = new Bundle(outState); // make a copy
Application.putSaveInstanceState(TAG, bundle); // put into a container in my application class
outState.clear(); // do not pass to framework
}
2. Activity: onCreate(Bundle savedInstanceState):
if (os >= Android 7) {
savedInstanceState = Application.getSaveInstanceState(TAG);
// if the application was dead, this will be null, in this case we just don't want to crash by framework. the cost is losing user's navigation state.
// if application is not dead, everything is fine.
}
super.onCreate(savedInstanceState); // it restores fragments and views if available
TransactionTooLargeException will be thrown if there's too many fragments (deep backstack).
SavedInstanceState becomes useless. The real solution is to abandon it.
1. Activity: onSaveInstanceState(Bundle outState):
super.onSaveInstanceState(outState); // it'll collect saved state from fragments and views
if (os >= Android 7) {
Bundle bundle = new Bundle(outState); // make a copy
Application.putSaveInstanceState(TAG, bundle); // put into a container in my application class
outState.clear(); // do not pass to framework
}
2. Activity: onCreate(Bundle savedInstanceState):
if (os >= Android 7) {
savedInstanceState = Application.getSaveInstanceState(TAG);
// if the application was dead, this will be null, in this case we just don't want to crash by framework. the cost is losing user's navigation state.
// if application is not dead, everything is fine.
}
super.onCreate(savedInstanceState); // it restores fragments and views if available
TransactionTooLargeException will be thrown if there's too many fragments (deep backstack).
SavedInstanceState becomes useless. The real solution is to abandon it.
tg...@woolworths.com.au <tg...@woolworths.com.au> #65
[Comment deleted]
tg...@woolworths.com.au <tg...@woolworths.com.au> #66
I am sharing one large string from Activity A to B. This case I got crash If have any solution please reply to me
crash Log :
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 614232 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3755)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6088)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: android.os.TransactionTooLargeException: data parcel size 614232 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3628)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3747)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6088)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
crash Log :
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 614232 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3755)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6088)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: android.os.TransactionTooLargeException: data parcel size 614232 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3628)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3747)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6088)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
ke...@gmail.com <ke...@gmail.com> #67
@tgane...
1. If these two Activity are in the same application:
a. Make a reference which both Activity can access. Be careful to avoid memory leaks. Maybe try some 3rd-party libraries, for example, EventBus.
b. Use SharedPreferences / SQLiteDatabase / ContentProvider / File ... depends on your need.
2. Else, maybe try to pass the Uri. It'll depends on the receiver side. To provide the Uri, maybe you'll need to implement a FileProvider or something else.
1. If these two Activity are in the same application:
a. Make a reference which both Activity can access. Be careful to avoid memory leaks. Maybe try some 3rd-party libraries, for example, EventBus.
b. Use SharedPreferences / SQLiteDatabase / ContentProvider / File ... depends on your need.
2. Else, maybe try to pass the Uri. It'll depends on the receiver side. To provide the Uri, maybe you'll need to implement a FileProvider or something else.
[Deleted User] <[Deleted User]> #68
Hey guys, I'm working on a utility to help with this issue.
My idea was the following:
- take the bundle provided by Android in onSaveInstanceState and put an ID in it
- provide and interface equivalent to Bundle, for drop-in replacement support of the current way onSaveInstanceState works
- take a bundle provided in onRestoreInstanceState, onCreate, onActivityCreated, onPostCreate etc. and attempt to restore the state using the ID stored inside it
NICE-TO-HAVE
- make the form the data is stored/retrieved in extensible/pluggable
- offer a good-enough default implementation
- prevent UI thread work if possible (not sure how to do this without requiring significant refactoring of the Activity/Fragment code)
- offer a way to clean up leftover state (if any), in case the application is destroyed
The goal is to have something that can be localized to just those lifecycle callbacks which pass around the saved state, and to make it as easy as possible to add with the least code change, while still performing reasonably well.
Now, just as a proof of concept I started off with writing the Bundle Parcel of the outState to a file, and then reading it back in from savedInstanceState. From a performance point of view, it's not THAT terrible, each file takes a couple of milliseconds to save, and this can of course add up depending on how many Fragments/Activities you have. But it's just a stop-gap measure until I figure out the API for this thing.
BUT, the issue that I'm having is that I thought I can just pass a different bundle forward to my baseclass, by calling super.onSaveInstanceState with a new one, which only contains a state ID, and not all of the data which was causing the crash - turns out that's not how it works, in the end, I always get the same Bundle passed back to me in onCreate regardless of what I pass forward in onSaveInstanceState, which really surprised me and it causing the API of this utility to become very convoluted and note very nice to use.
Any ideas?
My idea was the following:
- take the bundle provided by Android in onSaveInstanceState and put an ID in it
- provide and interface equivalent to Bundle, for drop-in replacement support of the current way onSaveInstanceState works
- take a bundle provided in onRestoreInstanceState, onCreate, onActivityCreated, onPostCreate etc. and attempt to restore the state using the ID stored inside it
NICE-TO-HAVE
- make the form the data is stored/retrieved in extensible/pluggable
- offer a good-enough default implementation
- prevent UI thread work if possible (not sure how to do this without requiring significant refactoring of the Activity/Fragment code)
- offer a way to clean up leftover state (if any), in case the application is destroyed
The goal is to have something that can be localized to just those lifecycle callbacks which pass around the saved state, and to make it as easy as possible to add with the least code change, while still performing reasonably well.
Now, just as a proof of concept I started off with writing the Bundle Parcel of the outState to a file, and then reading it back in from savedInstanceState. From a performance point of view, it's not THAT terrible, each file takes a couple of milliseconds to save, and this can of course add up depending on how many Fragments/Activities you have. But it's just a stop-gap measure until I figure out the API for this thing.
BUT, the issue that I'm having is that I thought I can just pass a different bundle forward to my baseclass, by calling super.onSaveInstanceState with a new one, which only contains a state ID, and not all of the data which was causing the crash - turns out that's not how it works, in the end, I always get the same Bundle passed back to me in onCreate regardless of what I pass forward in onSaveInstanceState, which really surprised me and it causing the API of this utility to become very convoluted and note very nice to use.
Any ideas?
ke...@gmail.com <ke...@gmail.com> #69
[Comment deleted]
ke...@gmail.com <ke...@gmail.com> #70
[Comment deleted]
ke...@gmail.com <ke...@gmail.com> #71
@m.divko...
Seehttps://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/ActivityThread.java#4533
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/Instrumentation.java#1299
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/Activity.java#1413
ActivityThread calls YourActivity.onSaveInstanceState() with Bundle A -> you call super.onSaveInstanceState with new Bundle B -> the base class put state into Bundle B -> ... -> YourActivity.onSaveInstanceState() is done.
Next time ActivityThread calls YourActivity.onCreate() with Bundle A, that's why you always get the same bundle. The return type of onSaveInstanceState(Bundle outState) is void.
See
ActivityThread calls YourActivity.onSaveInstanceState() with Bundle A -> you call super.onSaveInstanceState with new Bundle B -> the base class put state into Bundle B -> ... -> YourActivity.onSaveInstanceState() is done.
Next time ActivityThread calls YourActivity.onCreate() with Bundle A, that's why you always get the same bundle. The return type of onSaveInstanceState(Bundle outState) is void.
da...@gmail.com <da...@gmail.com> #72
@m.divko.., Are you able to save a Bundle to a file and retrieve it back without a change in its structure?? If so, how did you do it?
ch...@gmail.com <ch...@gmail.com> #73
[Comment deleted]
[Deleted User] <[Deleted User]> #74
[Comment deleted]
[Deleted User] <[Deleted User]> #75
The arguments Bundle of all fragments referenced by the fragment manager are written to the shared buffer during `Activity#onSaveInstanceState(Bundle)`.
I have just been fixing a crash in the Guardian Android app due to a `TransactionTooLargeException` being thrown during `onSaveInstanceState`. It was pretty tricky to debug because the only state our app code was writing was trivial (a few integers and boolean flags). But as I said above, the arguments of all the fragments are also written (by the `FragmentActivity` base class) to `outState` and this was causing the crash in our case.
Perhaps this will be helpful to some of you, or future visitors to this page.
I have just been fixing a crash in the Guardian Android app due to a `TransactionTooLargeException` being thrown during `onSaveInstanceState`. It was pretty tricky to debug because the only state our app code was writing was trivial (a few integers and boolean flags). But as I said above, the arguments of all the fragments are also written (by the `FragmentActivity` base class) to `outState` and this was causing the crash in our case.
Perhaps this will be helpful to some of you, or future visitors to this page.
[Deleted User] <[Deleted User]> #76
Hi all, I've tidied up some of the code I used whilst debugging this issue and created the "toolargetool" which attempts to log all the values, and their sizes, as their being written to the transaction buffer.
Check out toolargetool here:https://github.com/guardian/toolargetool
Check out toolargetool here:
[Deleted User] <[Deleted User]> #77
Hello everyone!
The TransactionTooLargeException has been plaguing us for about 4 months now, and we've finally resolved the issue!
What was happening was we are using a FragmentStatePagerAdapter in a ViewPager. The user would page through and create 100+ fragments (its a reading application).
Although we manage the fragments properly in destroyItem(), in Androids
implementation of FragmentStatePagerAdapter there is a bug, where it kept a reference to the following list:
private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
And when the Android's FragmentStatePagerAdapter attempts to save the state, it will call the function
@Override
public Parcelable saveState() {
Bundle state = null;
if (mSavedState.size() > 0) {
state = new Bundle();
Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
mSavedState.toArray(fss);
state.putParcelableArray("states", fss);
}
for (int i=0; i<mFragments.size(); i++) {
Fragment f = mFragments.get(i);
if (f != null && f.isAdded()) {
if (state == null) {
state = new Bundle();
}
String key = "f" + i;
mFragmentManager.putFragment(state, key, f);
}
}
return state;
}
As you can see, even if you properly manage the fragments in the FragmentStatePagerAdapter subclass, the base class will still store an Fragment.SavedState for every single fragment ever created. The TransactionTooLargeException would occur when that array was dumped to a parcelableArray and the OS wouldn't like it 100+ items.
Therefore the fix for us was to override the saveState() method and not store anything for "states".
@Override
public Parcelable saveState() {
Bundle bundle = (Bundle) super.saveState();
bundle.putParcelableArray("states", null); // Never maintain any states from the base class, just null it out
return bundle;
}
The TransactionTooLargeException has been plaguing us for about 4 months now, and we've finally resolved the issue!
What was happening was we are using a FragmentStatePagerAdapter in a ViewPager. The user would page through and create 100+ fragments (its a reading application).
Although we manage the fragments properly in destroyItem(), in Androids
implementation of FragmentStatePagerAdapter there is a bug, where it kept a reference to the following list:
private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
And when the Android's FragmentStatePagerAdapter attempts to save the state, it will call the function
@Override
public Parcelable saveState() {
Bundle state = null;
if (mSavedState.size() > 0) {
state = new Bundle();
Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
mSavedState.toArray(fss);
state.putParcelableArray("states", fss);
}
for (int i=0; i<mFragments.size(); i++) {
Fragment f = mFragments.get(i);
if (f != null && f.isAdded()) {
if (state == null) {
state = new Bundle();
}
String key = "f" + i;
mFragmentManager.putFragment(state, key, f);
}
}
return state;
}
As you can see, even if you properly manage the fragments in the FragmentStatePagerAdapter subclass, the base class will still store an Fragment.SavedState for every single fragment ever created. The TransactionTooLargeException would occur when that array was dumped to a parcelableArray and the OS wouldn't like it 100+ items.
Therefore the fix for us was to override the saveState() method and not store anything for "states".
@Override
public Parcelable saveState() {
Bundle bundle = (Bundle) super.saveState();
bundle.putParcelableArray("states", null); // Never maintain any states from the base class, just null it out
return bundle;
}
mo...@gmail.com <mo...@gmail.com> #78
I do get that the TransactionTooLargeException is required (albeit a tad too late to implement it), but I think the exception should be thrown earlier in the stack.
Right now it is thrown by the BinderProxy in the android.os and the stack only consists of the android native calls. If developers should mitigate this, there should be an earlier exception thrown.
Just my two cents in what I find to be poor code decision making from Google's side.
Right now it is thrown by the BinderProxy in the android.os and the stack only consists of the android native calls. If developers should mitigate this, there should be an earlier exception thrown.
Just my two cents in what I find to be poor code decision making from Google's side.
ak...@gmail.com <ak...@gmail.com> #79
Although I haven't found the fix, i've noticed that 90% of it is from Samsung devices only. Is anyone else seeing that pattern?
Also i'm wondering if theres a UI related library that all of us are using which could potentially be causing this. My best bet would be the support library. Anyone here NOT using the support library facing the issue?
Also i'm wondering if theres a UI related library that all of us are using which could potentially be causing this. My best bet would be the support library. Anyone here NOT using the support library facing the issue?
mx...@gmail.com <mx...@gmail.com> #80
I have been facing the same issue for some time now using fragment state adapters, well obviously based on the size of my classes I've had to set the maximum size of my response list data to a maximum of 25 for each tab out of 5 which all have pagination (With the current size of each model I can save a maximum of 40 for each page before I get the exception). This only delays the inevitable TransactionTooLargeException when I go deeper into other activities to view details of a list item etc.
I've see the exception on Sony, Xiaomi, Samsung and other devices each of them always throwing the exception with different limits sometimes a little over 1MB sometimes as little as 700KB I've managed to get away with a fair deal of saving some model objects inside a presenter which only gets it's instance created in the onCreate() of my fragments and only save these objects in the onPause() but this too is far from anything close to a solution.
I understand that the android system has a 1MB size limit for the mechanism that handles save states or send intent data across activities, can't remember what it was called and I'm sure it's not as straight forward to increase that limit, but maybe if we could have something like an extremely fast object parser (faster than parcelable?) to allow an increased size of objects saved without taxing cpu io wait time? I have no idea if what I'm saying is even sensible.
Out of curiosity though, in respect to networking has anyone tried to using any caching mechanisms like rxcache in attempts to solve this?
I've see the exception on Sony, Xiaomi, Samsung and other devices each of them always throwing the exception with different limits sometimes a little over 1MB sometimes as little as 700KB I've managed to get away with a fair deal of saving some model objects inside a presenter which only gets it's instance created in the onCreate() of my fragments and only save these objects in the onPause() but this too is far from anything close to a solution.
I understand that the android system has a 1MB size limit for the mechanism that handles save states or send intent data across activities, can't remember what it was called and I'm sure it's not as straight forward to increase that limit, but maybe if we could have something like an extremely fast object parser (faster than parcelable?) to allow an increased size of objects saved without taxing cpu io wait time? I have no idea if what I'm saying is even sensible.
Out of curiosity though, in respect to networking has anyone tried to using any caching mechanisms like rxcache in attempts to solve this?
br...@livefront.com <br...@livefront.com> #81
For anyone who is seeing this crash due to too much data being placed in the saved state Bundle, I've created a quick library that gets around the crash by wrapping popular annotation-base state saving solutions like Icepick :
https://github.com/livefront/bridge
If you are already using Icepick or something like it, the code changes in your app should be minimal. The library can also be used even if you are not using Icepick, but it would require a bit more work such that it would probably be easiest to just start using Icepick anyway.
If you are already using Icepick or something like it, the code changes in your app should be minimal. The library can also be used even if you are not using Icepick, but it would require a bit more work such that it would probably be easiest to just start using Icepick anyway.
st...@gmail.com <st...@gmail.com> #82
With Android O Dp4 i could not be able to replicate the issue, maybe it was fixed
Can anyone confirm?
Can anyone confirm?
sa...@gmail.com <sa...@gmail.com> #83
@Override
public void onSaveInstanceState(Bundle stateBundle) {
int osVersion = android.os.Build.VERSION.SDK_INT;
if ( osVersion < Build.VERSION_CODES.N) {
super.onSaveInstanceState(stateBundle);
}
}
Above code fixed my issue :D
public void onSaveInstanceState(Bundle stateBundle) {
int osVersion = android.os.Build.VERSION.SDK_INT;
if ( osVersion < Build.VERSION_CODES.N) {
super.onSaveInstanceState(stateBundle);
}
}
Above code fixed my issue :D
ma...@gmail.com <ma...@gmail.com> #84
@ #83 That doesn't fix it, you've just swept it under the rug.
go...@schildbach.de <go...@schildbach.de> #85
@st...@gmail.com Indeed, I get tons of bugreports of this on my app for N, but so far nothing for O. I suspect this has silently been fixed.
br...@livefront.com <br...@livefront.com> #86
I did a little testing on a Pixel with Oreo and I'm still seeing it.
to...@googlemail.com <to...@googlemail.com> #87
@ Comment #85 (go...@schildbach.de) I can not confirm that. I just tested our application on an Android Oreo emulator. TransactionTooLargeException is still thrown in the same places as in Android Nougat.
an...@gmail.com <an...@gmail.com> #88
For my understanding this issue will not be never fixed because according to it status its a feature but not a bug.
Status - *Won't Fix (Intended behavior)*
Status - *Won't Fix (Intended behavior)*
[Deleted User] <[Deleted User]> #89
Is there a way to find what is the size of saved state for an Activity or Fragment at a given point of time?
an...@gmail.com <an...@gmail.com> #90
To my mind there is one approach only on that. Summarize all bundle's elements sizes.
br...@livefront.com <br...@livefront.com> #91
You can check the size of your Bundle in onSaveInstanceState by writing to a Parcel and checking its "dataSize":
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
...
Parcel parcel = Parcel.obtain();
parcel.writeBundle(outState);
int sizeInBytes = parcel.dataSize(); // This is what you want to check
parcel.recycle();
}
When that value gets over roughly 0.5 MB for a single Activity, you start to have problems.
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
...
Parcel parcel = Parcel.obtain();
parcel.writeBundle(outState);
int sizeInBytes = parcel.dataSize(); // This is what you want to check
parcel.recycle();
}
When that value gets over roughly 0.5 MB for a single Activity, you start to have problems.
ev...@universo.univates.br <ev...@universo.univates.br> #92
2k20 and its still the same problem, congrats.
ar...@rizek.com <ar...@rizek.com> #93
Its Reproducing all the time
ak...@gmail.com <ak...@gmail.com> #94
This debugging library can be very useful in locating large bundles: https://github.com/guardian/toolargetool
c_...@costco.com <c_...@costco.com> #95
I have been reporting similar crashes due to “android.os.TransactionTooLargeException” from firebase Crashlytics on the below devices –
OS version: android14
Devices_Model: Pixel 6a, Galaxy A53 5G, Galaxy S23, Galaxy S24+ and Galaxy Z Fold5
OS version: android13
Devices_Model: Galaxy Tab S7+ and Galaxy S20 FE 5G
Do we have any proposed solution by Google or is it being expected in future?
Here is the detail exception –
Caused by android.os.TransactionTooLargeException: data parcel size 1570564 bytes
at android.os.BinderProxy.transactNative(BinderProxy.java)
at android.os.BinderProxy.transact(BinderProxy.java:662)
at android.app.IActivityClientController$Stub$Proxy.activityStopped(IActivityClientController.java:1507)
at android.app.ActivityClient.activityStopped(ActivityClient.java:100)
at android.app.servertransaction.PendingTransactionActions$StopInfo.run(PendingTransactionActions.java:135)
at android.os.Handler.handleCallback(Handler.java:958)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8919)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
OS version: android14
Devices_Model: Pixel 6a, Galaxy A53 5G, Galaxy S23, Galaxy S24+ and Galaxy Z Fold5
OS version: android13
Devices_Model: Galaxy Tab S7+ and Galaxy S20 FE 5G
Do we have any proposed solution by Google or is it being expected in future?
Here is the detail exception –
Caused by android.os.TransactionTooLargeException: data parcel size 1570564 bytes
at android.os.BinderProxy.transactNative(BinderProxy.java)
at android.os.BinderProxy.transact(BinderProxy.java:662)
at android.app.IActivityClientController$Stub$Proxy.activityStopped(IActivityClientController.java:1507)
at android.app.ActivityClient.activityStopped(ActivityClient.java:100)
at android.app.servertransaction.PendingTransactionActions$StopInfo.run(PendingTransactionActions.java:135)
at android.os.Handler.handleCallback(Handler.java:958)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8919)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
Description
This form is only for reporting bugs found in the Android system while
developing Android applications. Use the Tools templates for issues with
the developer tools.
Please describe the problem in detail. Be sure to include:
- Steps to reproduce the problem (including sample code if appropriate).
1> Load the Android N target build of the Target application (com.target.ui)
2> Search for a product by term "beer", etc
3> Scroll down through list of resultant products
4> Click device home button
- What happened.
After reaching the home screen, crash prompt came up "Target has stopped". Here is the crash stack trace:
android.os.TransactionTooLargeException: data parcel size 680544 bytes
at android.os.BinderProxy.transactNative()(Binder.java:-2)
at android.os.BinderProxy.transact()(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped()(ActivityManagerNative.java:3579)
at android.app.ActivityThread$StopInfo.run()(ActivityThread.java:3718)
at android.os.Handler.handleCallback()(Handler.java:751)
at android.os.Handler.dispatchMessage()(Handler.java:95)
at android.os.Looper.loop()(Looper.java:154)
at android.app.ActivityThread.main()(ActivityThread.java:5969)
at java.lang.reflect.Method.invoke()(Method.java:-2)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run()(ZygoteInit.java:801)
at com.android.internal.os.ZygoteInit.main()(ZygoteInit.java:691)
- What you think the correct behavior should be.
should not crash
Don't forget to mention which version of Android you're using, and/or which
device the problem appears on (model and Android version).
Appeared on Pixel C and Nexus 5x running Android N preview 3 Build Number NPD35k
Please also run "adb bugreport" and archive the output.