livefront / bridge Goto Github PK
View Code? Open in Web Editor NEWAn Android library for avoiding TransactionTooLargeException during state saving and restoration
License: Apache License 2.0
An Android library for avoiding TransactionTooLargeException during state saving and restoration
License: Apache License 2.0
Sorry, maybe this is a newbish question and maybe it is not about your library at all, but I don't understand how to use Bridge with Icekick you mentioned. Icekick provides only the extensions for View, Activity, Fragment. And I cannot setup it globally in Application class
Bridge.initialize(applicationContext, object : SavedStateHandler {
override fun restoreInstanceState(@NonNull target: Any, @NonNull state: Bundle?) {
// what to write here?
}
override fun saveInstanceState(@NonNull target: Any, @NonNull state: Bundle) {
// what to write here?
}
})
I am just trying to use library without EPL license.
Hi,
We just upgraded to the latest version of Bridge and we're seeing this crash in production. No repro steps yet, but here's the callstack:
java.lang.NullPointerException: Attempt to read from field 'java.util.concurrent.Future f.n.a.j.b.b' on a null object reference
at com.livefront.bridge.disk.FileDiskHandler.cancelFileLoading(FileDiskHandler:120)
at com.livefront.bridge.disk.FileDiskHandler.clearAll(FileDiskHandler:70)
at com.livefront.bridge.BridgeDelegate$1.run(BridgeDelegate:98)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
I could submit a PR for a simple null check, but maybe you have some deeper idea of what's going on.
Hi there! Thanks for this library, it's helped a lot.
We had to add the GET_TASKS permission as it's required to use the getRunningTasks()
for Android 4.4 and below else it crashes. I don't think there's a way to add the permission for only devices running Android 4.4 and below.
We're about to publish a release but the Google Play pre-launch report but it's flagged an error.
Your app is requesting permissions which are used by less than 1% of functionally similar apps:
android.permission.GET_TASKS
Users prefer apps that request fewer permissions and requesting unnecessary permissions can affect your app's visibility on the Play Store. If these permissions aren't necessary, you may be able to use alternative methods in your app and request fewer permissions. If they are, we recommend providing an explanation to users of why you need the permissions.Note: This guidance is based on a comparison with functionally similar apps, which change over time as new apps get published and existing apps change behavior. Therefore the warning may change even if you don't change your permission usage.
We can explain the reason behind this but it could be a privacy concern for our users.
In the document, it recommends to use Bridge.clear(this)
during onDestroy.
@Override
public void onDestroy() {
super.onDestroy();
Bridge.clear(this);
}
I tried it, and it clear the saved data as onDestroy
is called when the system kill the Activity. So when restoring, the saved data is no longer available.
all the device i have tested my code with this library its working fine but mi one when i am switching my activity or i am going background again forground my previous activity data vanished .....
please anyone help me with this issue ... its happening only in mi os verion 7.1.2
Currently the Bridge.clear()
method requires a reference to the target object in order to clear its data. Typically this method would be called in the onDestroy
method of a particular Activity
or Fragment
that is about to be discarded. There are cases, however, where this may delete data that is still needed. For example, when using a FragmentStatePagerAdapter, each Fragment
is "destroyed" when it is no longer actively being viewed but its saved state Bundle
may be saved in order to reconstruct that Fragment
again later. In these cases we should provide a way for a caller to manually specify a "clearing tag" to associate with the saved data. This tag could then be used later to actually clear the data. In the FragmentStatePagerAdapter
example, the data could be cleared in the onDestroy
of the parent Activity
with a call like Bridge.clearForTag("tag")
.
Hello, i am using the bridge library with Icepick. itΒ΄s seem me that is working fine in 95 % of my application.
But, i have a activity that use one TabHost. For each tab of my component i create a instance of fragment and then i atach or detach depending on visibility of the tab.
Usually, i have 5 fragments created at same time.
Sometimes, the exception occurs.
i am using the bridge in my activity on methods OnCreate and onSaveInstanceState.
Do you have some ideia for this case ? Does the bridge work inside fragments ?
When used with android-state library, and when that library is enabled globally (StateSaver.setEnabledForAllActivitiesAndSupportFragments(this, true)
) the TransactionTooLargeException
still occurs.
Sample code:
MyActivity.java:
@State
public String big = new String(new char[1_000_000]);
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Bridge.saveInstanceState(this, outState);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bridge.restoreInstanceState(this, savedInstanceState);
}
MyApplication.java:
@Override
public void onCreate() {
super.onCreate();
// If you comment out the following line, it all works properly
StateSaver.setEnabledForAllActivitiesAndSupportFragments(this, true);
Bridge.initialize(getApplicationContext(), new SavedStateHandler() {
@Override
public void saveInstanceState(@NonNull Object target, @NonNull Bundle state) {
StateSaver.saveInstanceState(target, state);
}
@Override
public void restoreInstanceState(@NonNull Object target, @Nullable Bundle state) {
StateSaver.restoreInstanceState(target, state);
}
});
}
Thanks for this library. I'm currently trying to fix issues with ViewPager containing large amount of pages and not using a state saving library so doing it by hand as suggested in #14.
Is there a way to get
the Bundle
stored by Bridge? I use the state in onCreate()
to restore the underlying data which for whatever reason couldn't be used in onRestoreInstanceState()
therefore I can't refactor very easily the code to use just restoreState(Bundle)
. Could you point me in the direction I'd need to go if I just wanted the Bundle
, please?
Thanks!
The GET_TASKS
permission appears to be required to call getRunningTasks()
for Android 4.4 and below. This should be called out in the README
.
See #59 for more details.
Hi!
We have ANRs in our Crashlytics. All devices running Android 12 and 13. 66% of them are Samsung devices ))
Could you please help to find the reason of these ANRs )
main (timed waiting):tid=1 systid=25492
at jdk.internal.misc.Unsafe.park(Unsafe.java)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:234)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos(AbstractQueuedSynchronizer.java:1079)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos(AbstractQueuedSynchronizer.java:1369)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:278)
at com.livefront.bridge.BridgeDelegate.queueDiskWritingIfNecessary(BridgeDelegate.java:229)
at com.livefront.bridge.BridgeDelegate.saveToMemoryAndDiskIfNecessary(BridgeDelegate.java:380)
at com.livefront.bridge.BridgeDelegate.saveInstanceState(BridgeDelegate.java:348)
at com.livefront.bridge.Bridge.saveInstanceState(Bridge.java:145)
systid=25492
- it's different in each case. Other parts of stack-trace are the same.
we use following code to init Bridge
private fun initBridge() {
Bridge.initialize(this, object : SavedStateHandler {
override fun saveInstanceState(target: Any, state: Bundle) {
(target as? StateSaver)?.saveState(state)
}
override fun restoreInstanceState(target: Any, state: Bundle?) {
(target as? StateSaver)?.restoreState(state)
}
})
}
Where StateSaver
is interface which is implemented by our Fragments
// BaseFragment
override fun onSaveInstanceState(outState: Bundle) {
Bridge.saveInstanceState(this, outState)
}
Hi @byencho ,
When used with icepick library, the TransactionTooLargeException still occurs.
Sample Code:
MyActivity.java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bridge.restoreInstanceState(this, savedInstanceState);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Bridge.saveInstanceState(this, outState);
}
@Override
public void onDestroy() {
super.onDestroy();
Bridge.clear(this);
}
MyApplication.java:
import icepick.Icepick;
import com.livefront.bridge.Bridge;
import com.livefront.bridge.SavedStateHandler;
@Override
public void onCreate() {
super.onCreate();
Bridge.initialize(getApplicationContext(), new SavedStateHandler() {
@Override
public void restoreInstanceState(@NonNull Object target, @Nullable Bundle state) {
Icepick.restoreInstanceState(target, state);
}
@Override
public void saveInstanceState(@NonNull Object target, @NonNull Bundle state) {
Icepick.saveInstanceState(target, state);
}
});
}
It is a react native app with single activity.
dependencies {
compile 'com.github.livefront:bridge:v1.1.3'
compile 'frankiesardo:icepick:3.2.0'
annotationProcessor 'frankiesardo:icepick-processor:3.2.0'
}
Can't really replicate this issue, but reported quite a bit of instance error log
Fatal Exception: java.lang.OutOfMemoryError: Failed to allocate a 9740048 byte allocation with 7449136 free bytes and 7MB until OOM
at java.lang.StringFactory.newStringFromChars + 218(StringFactory.java:218)
at java.lang.StringFactory.newStringFromBytes + 203(StringFactory.java:203)
at java.lang.StringFactory.newStringFromBytes + 63(StringFactory.java:63)
at android.util.Base64.encodeToString + 456(Base64.java:456)
at com.livefront.bridge.BridgeDelegate.writeToDisk + 171(BridgeDelegate.java:171)
at com.livefront.bridge.BridgeDelegate.saveInstanceState + 164(BridgeDelegate.java:164)
at com.livefront.bridge.Bridge.saveInstanceState + 80(Bridge.java:80)
I am not using any android state library like icepick as saved state handler. But was directly keeping data to bundle using putParcelable, putByteArray etc. In this case how to use bridge library. I have integrated your library and for test purpose added data to bundle (like savedInstanceState.putByteArray("bytes", new byte[1000 * 1000]);) and have used Bridge to save my bundle eg Bridge.saveInstanceState(this, savedInstanceState);
When i checked the log i am still getting TransactionTooLargeException
This is another 2.0 crash that we're seeing in production. No local repro yet. It seems to occur mostly on OS 8.1.0 and 7.0 but it's happening across OS levels.
Caused by: java.lang.IllegalArgumentException
at android.os.Parcel.nativeAppendFrom(Parcel.java:-2)
at android.os.Parcel.appendFrom(Parcel.java:446)
at android.os.BaseBundle.readFromParcelInner(BaseBundle.java:1356)
at android.os.BaseBundle.<init>(BaseBundle.java:90)
at android.os.Bundle.<init>(Bundle.java:68)
at android.os.Parcel.readBundle(Parcel.java:1704)
at com.livefront.bridge.util.BundleUtil.fromBytes(BundleUtil:58)
at com.livefront.bridge.BridgeDelegate.readFromDisk(BridgeDelegate:241)
at com.livefront.bridge.BridgeDelegate.getSavedBundleAndUnwrap(BridgeDelegate:138)
at com.livefront.bridge.BridgeDelegate.restoreInstanceState(BridgeDelegate:302)
at com.livefront.bridge.Bridge.restoreInstanceState(Bridge:111)
<our code>
Any ideas?
Hello @brian-livefront !
I'm not sure that this issue is about Bridge, but there is a chance that it is somehow related to Bridge))
We started to receive 2 kinds of crashes when we bumped the target SDK to 33.
As I can see crash occurs when the app comes back from the background and Activity is recreated together with Fragments.
I tried to reproduce it with "Don't keep Activities" flag turned ON, but I couldn't...
Devices: Samsung (38%), Xiaomi (38%), Motorola (8%), Oppo (5%), ...
OS: Android 12 (48%), 11 (27%), 10 (16%), 9 (7%), ...
Android 8-12
Fatal Exception: java.lang.RuntimeException
Unable to start activity ComponentInfo{SingleFragmentActivity}: java.lang.RuntimeException: Parcel android.os.Parcel@952ddad: Unmarshalling unknown type code 57 at offset 2204
Caused by java.lang.RuntimeException
Parcel android.os.Parcel@322d31a: Unmarshalling unknown type code 57 at offset 2204
android.os.Parcel.readValue (Parcel.java:3318)
android.os.Parcel.readSparseArrayInternal (Parcel.java:3719)
android.os.Parcel.readSparseArray (Parcel.java:2857)
android.os.Parcel.readValue (Parcel.java:3296)
android.os.Parcel.readArrayMapInternal (Parcel.java:3636)
android.os.BaseBundle.initializeFromParcelLocked (BaseBundle.java:292)
android.os.BaseBundle.unparcel (BaseBundle.java:236)
android.os.Bundle.getSparseParcelableArray (Bundle.java:1080)
androidx.fragment.app.FragmentStateManager.restoreState (FragmentStateManager.java:408)
androidx.fragment.app.FragmentManager.restoreSaveStateInternal (FragmentManager.java:2512)
androidx.fragment.app.Fragment.restoreChildFragmentState (Fragment.java:1989)
androidx.fragment.app.Fragment.onCreate (Fragment.java:1965)
com.myapp.presentation.base.MviCoreFragment.onCreate (MviCoreFragment.kt:149)
com.myapp.presentation.main.MainFragment.onCreate (MainFragment.kt:55)
androidx.fragment.app.Fragment.performCreate (Fragment.java:3090)
androidx.fragment.app.FragmentStateManager.create (FragmentStateManager.java:475)
androidx.fragment.app.FragmentStateManager.moveToExpectedState (FragmentStateManager.java:257)
androidx.fragment.app.FragmentStore.moveToExpectedState (FragmentStore.java:113)
androidx.fragment.app.FragmentManager.moveToState (FragmentManager.java:1433)
androidx.fragment.app.FragmentManager.dispatchStateChange (FragmentManager.java:2977)
androidx.fragment.app.FragmentManager.dispatchCreate (FragmentManager.java:2884)
androidx.fragment.app.FragmentController.dispatchCreate (FragmentController.java:252)
androidx.fragment.app.FragmentActivity.onCreate (FragmentActivity.java:220)
com.myapp.presentation.base.MviCoreActivity.onCreate (MviCoreActivity.kt:81)
com.myapp.presentation.singlefragment.SingleFragmentActivity.onCreate (SingleFragmentActivity.kt:46)
android.app.Activity.performCreate (Activity.java:8290)
android.app.Activity.performCreate (Activity.java:8270)
android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1329)
android.app.ActivityThread.performLaunchActivity (ActivityThread.java:4085)
android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:4277)
android.app.servertransaction.LaunchActivityItem.execute (LaunchActivityItem.java:103)
android.app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor.java:135)
android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:95)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2443)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:226)
android.os.Looper.loop (Looper.java:313)
android.app.ActivityThread.main (ActivityThread.java:8751)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:571)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1135)
Devices: Samsung (71%), Google(18%), Xiaomi (5%), Oppo (2%), ...
OS: Android 13
1 second after start
Android 13
Fatal Exception: java.lang.RuntimeException
Unable to start activity ComponentInfo{SingleFragmentActivity}: android.os.BadParcelableException: Parcel android.os.Parcel@d6c614b: Unmarshalling unknown type code 3014757 at offset 2736
Caused by android.os.BadParcelableException
Parcel android.os.Parcel@d6c614b: Unmarshalling unknown type code 3014757 at offset 2736
android.os.Parcel.readValue (Parcel.java:4696)
android.os.Parcel.readValue (Parcel.java:4355)
android.os.Parcel.readSparseArrayInternal (Parcel.java:5411)
android.os.Parcel.readValue (Parcel.java:4651)
android.os.Parcel.readValue (Parcel.java:4347)
android.os.Parcel.-$$Nest$mreadValue
android.os.Parcel$LazyValue.apply (Parcel.java:4445)
android.os.Parcel$LazyValue.apply (Parcel.java:4404)
android.os.BaseBundle.getValueAt (BaseBundle.java:394)
android.os.BaseBundle.getValue (BaseBundle.java:374)
android.os.BaseBundle.getValue (BaseBundle.java:357)
android.os.BaseBundle.getValue (BaseBundle.java:350)
android.os.Bundle.getSparseParcelableArray (Bundle.java:1108)
androidx.fragment.app.FragmentStateManager.restoreState (FragmentStateManager.java:408)
androidx.fragment.app.FragmentManager.restoreSaveStateInternal (FragmentManager.java:2512)
androidx.fragment.app.Fragment.restoreChildFragmentState (Fragment.java:1989)
androidx.fragment.app.Fragment.onCreate (Fragment.java:1965)
com.myapp.presentation.base.MviCoreFragment.onCreate (MviCoreFragment.kt:149)
com.myapp.presentation.main.MainFragment.onCreate (MainFragment.kt:55)
androidx.fragment.app.Fragment.performCreate (Fragment.java:3090)
androidx.fragment.app.FragmentStateManager.create (FragmentStateManager.java:475)
androidx.fragment.app.FragmentStateManager.moveToExpectedState (FragmentStateManager.java:257)
androidx.fragment.app.FragmentStore.moveToExpectedState (FragmentStore.java:113)
androidx.fragment.app.FragmentManager.moveToState (FragmentManager.java:1433)
androidx.fragment.app.FragmentManager.dispatchStateChange (FragmentManager.java:2977)
androidx.fragment.app.FragmentManager.dispatchCreate (FragmentManager.java:2884)
androidx.fragment.app.FragmentController.dispatchCreate (FragmentController.java:252)
androidx.fragment.app.FragmentActivity.onCreate (FragmentActivity.java:220)
com.myapp.presentation.base.MviCoreActivity.onCreate (MviCoreActivity.kt:81)
com.myapp.presentation.singlefragment.SingleFragmentActivity.onCreate (SingleFragmentActivity.kt:46)
android.app.Activity.performCreate (Activity.java:8341)
android.app.Activity.performCreate (Activity.java:8320)
android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1417)
android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3622)
android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3778)
android.app.servertransaction.LaunchActivityItem.execute (LaunchActivityItem.java:101)
android.app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor.java:138)
android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:95)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2303)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:201)
android.os.Looper.loop (Looper.java:288)
android.app.ActivityThread.main (ActivityThread.java:7884)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:936)
override fun onCreate(savedInstanceState: Bundle?) {
try {
Bridge.restoreInstanceState(this, savedInstanceState)
} catch (e: Exception) { /* state not recovered due to CancellationException */
}
super.onCreate(savedInstanceState)
}
I started to suspect Bridge because it also retrieves some data from Bundle
, I thought maybe the rest of the Bundle
is corrupted after we call Bridge.restoreInstanceState
π
I see that you retrieve only one String uuid from savedInstanceState
, but maybe it affects Bundle in Android 13 because of different classLoder
or some other reason?
Any suggestions would be appreciated! πππ
I have followed your instructions carefully but I keep getting the following error
java.lang.IllegalStateException: You must first call initialize before calling any other methods
The bridgeDelegate has the below functions
void restoreInstanceState(@NonNull Object target, @Nullable Bundle state) {
boolean isFirstRestoreCall = mIsFirstRestoreCall;
mIsFirstRestoreCall = false;
if (state == null) {
if (isFirstRestoreCall) {
mSharedPreferences.edit()
.clear()
.apply();
}
return;
}
// ... other codes
}
With this, we are suppose to call the restoreInstanceState
without checking the savedInstanceState
to help clear the sharedPreference, as we assume this is the state where it doesn't have state restoration needed.
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
Bridge.restoreInstanceState(this, savedInstanceState)
// .... other codes
}
However, there could be chance where isFirstRestoreCall
is true, and savedInstanceState
is also null, but it is actually in a restored state. This would cause accidental removal of all saved and needed sharedPreference
This issue is further describe in https://medium.com/@elye.project/handling-transactiontoolargeexception-with-livefront-bridge-a846459420bb, the Uses restoreInstanceState to help clear the data is called without StateRestoration
section
For example, if we have a Fragment used in an adapter in which for every adapter position a new instance of that fragment is created, we cannot use Bridge in that Fragment.
On the first onDestroy event of any of the instances, all the instance state of every fragment is deleted. Also, every time we save the instance state of one of the fragments, the fragment's state of the previous view is lost. I think it's because you use "target.getClass().getName()" for identifying the target object.
Or, I can be wrong and doing something wrong.
I'm trying to apply this library without any other state handler library. Is there any workaround to implement it compatible with old style savedInstanceState methods when initializing it? Something like;
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Bridge.saveInstanceState(this, outState);
outState.putParcelable("hugeObject", hugeObject);
}
As i test, it causes TransactionTooLarge in any case, if there's no @State annotation for objects. Icepick is super nice but i have almost 200 unique activity in my project and lazy to overhaul all :)
is this library only for saving/restoring state or can i use it to transfer data between activities?
please provide an example if possible
android.preference
is deprecated as of Android 10. π
Do you plan to migrate?
see: https://developer.android.com/about/versions/10/behavior-changes-all#preferences
Hey, I have used both and bridge and Icepick but still getting the error. I have initialized bridge in Application class and then in my activity class I have a fragment pager adapter and for that fragment, I have used restore and save methods but as soon as I am putting my application in the background it gets crashed because of transition too large exception.
Any other help on this if I am missing something related to FragmentPagerAdapter.
I have also tried saveState approach for the adapter but no success.
I'm trying to implement Bridge for the app I'm building. Currently I use Icepick, which has an implementation for views defined in their documentation. Can I also use Bridge for these view instance state implementations?
When using a view pager or other libraries like this one the instance of the fragment i lost and when that happens the instance state saved on from bridge is cleared on the next onSaveInstanceState
call. Would be great if the BridgeDelegate.clearStaleData
call on the Bridge.onSaveInstanceState
could be optional.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.