I am using redux-persist
in a react native project, that runs just fine in a broad number of devices execept Android 7. I am trying to debug the problem on why my AsyncStorage is nor persisting and found this:
The following code executes inside React Native component lifecycle's
componentDidMount() {
attachObservables(store)
setInterval(async () => {
console.log('Inside setInterval')
const data = await AsyncStorage.getAllKeys()
console.log('inside the getAllKeys')
data.forEach(async k => {
const value = await AsyncStorage.getItem(k)
console.group(k)
console.log(value)
console.groupEnd()
})
}, 3000)
}
Code after 'Inside setInterval' is never called. It only runs once if outside the setInterval. If I call once the code outside the setInterval it appears to run just fine. I also tried callback format vs async / await version but it does not seem to matter.
Same problem I had using firebase js library (callbacks never return after the first one). I am now looking for alternatives to workaround the problem.
Works with setImmediate
and InteractionManager.runAfterInteractions
. Seems that redux-persist
uses setImmediate
or fallsback to setTimeout
.
Any ideas?
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
multiDexEnabled true
applicationId "com.netbeast.yeti"
minSdkVersion 16
targetSdkVersion 24
versionCode 69
versionName "1.3.91"
ndk {
abiFilters "armeabi-v7a", "x86"
}
}
In case this is a user level question I opened a question on stackoverflow, no luck yet, https://stackoverflow.com/questions/44114061/asyncstorage-is-not-returning-the-callback?noredirect=1#comment75248695_44114061
@jsdario any updates on this? were you able to work around or resolve the problem?
I was not able to fix it, but I cooked a heavy and chunky workaround. I simply reimplemented the AsyncStarage API around https://github.com/itinance/react-native-fs so we could use it as storage in redux-persist
.
Here it is the package https://github.com/netbeast/redux-persist-react-native-fs @dinzo
If I learn any more I'll share it. I have to say that we are using a set of advanced Android build tools, which might be the reason. The problem still exists on react-native 0.44 and 0.45.
I'm seeing this too. The promise returned by AsyncStorage.getItem()
just never resolves on Android. iOS is fine. I'm on RN 0.50RC.
Can confirm that I'm seeing this too. After doing a few bundle reloads, I start getting the Maximum call stack size exceeded
error.
I'm seeing this in RN-0.50.3. Trying to track down what precipitates it, because it doesn't happen all the time.
After further investigation: in my case I had an AsyncTask in some Java code (a local web server in my case) that was blocking and hence blocking other AsyncTasks (which AsyncStorage relies on). Setting my AsyncTask to execute in parallel to other tasks (via myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
instead of myTask.execute()
) fixed the issue.
I'll take a look and see if that'll solve my issue.
+1 Problem on android in react-native 0.50.3
problem still exists 50.3
I submitted a Pull Request with the proposed solution by @RickDT, so far it is working for me.
Thanks @jsdario .
One hack that may work is something like this:
const resolvedPromisesArray = [
AsyncStorage.getItem(TOKEN_KEY),
AsyncStorage.getItem(TOKEN_KEY),
AsyncStorage.getItem(TOKEN_KEY),
AsyncStorage.getItem(TOKEN_KEY),
AsyncStorage.getItem(TOKEN_KEY)
];
this.token = await Promise.race(resolvedPromisesArray);
Because it only seems to be happening sporadically, hitting it multiple times may give you a better chance of one of them resolving.
I know, this is very ugly 🥇
@jsdario waiting to merge your PR :) Thanks 👍
Update: But this does not completely solve the problem :(
How not? I am using it in production, can you further describe the issue @allmaxgit ?
I'm having this problem too. First time I execute the app code, AsyncStorage works fine, after few calls (4-5), getItem never call promise resolve function.
Might work once after freshly rebooting device. I have to find an alternative AsyncStorage doesn't work for me, which sucks because saving things on device is so important.
?FIXED
Updating to 0.51 appeared to fix this I was on 0.5.03
But
After reload android emulator with 'rr' it appears to break and I have to do react-native run-android again.
@UberMC I'm still having this problem on 0.51
any update on this, facing same issue with RN 0.50.0
same, did anyone figure a solution out ?
@julestruong I face this issue on Ubuntu on ejected project. Expo project is fine, projects on Windows also doesn't have any issues.
Seems like something is blocking the debugger port for AsyncStorage, hard to say exactly.
Hope this will help you.
Faced the same issue on emulator android 7 and device with android 7.
RN 0.50
hm... @RickDT where should I inject you code with myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
I dont make any other async task hm...
@Fortidude it will probably be in a 3rd party dependency, like an npm module that uses native Java code. Or Java code that you've introduced into the project.
One way to solve this for now is to have a completely separate interface for the development environment's storage where the async storage fails to function.
That's what I did – I got tired of figuring on solving the problem so I wrote a simple wrapper for the storage. The storage uses idb when the app is run in the development mode and the AsyncStorage if the remote debugger is disabled or running in production mode.
Feel free to use the wrapper I wrote (available on https://gitlab.com/snippets/1690090). I haven't had a single problem with the storage ever since I enabled this on my most recent RN project.
The only downside is that Reactotron fails to show the storage contents automatically since AsyncStorage isn't used.
How is progress on this issue? I'm seeing the same error on removing multiple keys and waiting with promise.all, it just never resolves
I'm having this problem too.
for me, i has been solved with 0.51
I'm having the same problem, using react native 0.51. I tried with multiSet and setItem both never resolve.
Facing the same issue in 0.50.3. Any solutions?
"react-native": "^0.52.0" facing the same issue.
You guys could check if my PR works for you? So far I believe it does work, it has been tested and commented by others, but not yet merged. Please, comment back if it works.
Interesting enough, I gave it a last shot and found a workaround.
npm start
on my terminalAlso:
react-native run-android
.Haven't been able to replicate issue at the moment.
react-native: 0.52.0
redux-persist: 5.4.0
edit: The issue is replicated when running a few reloads on hot reload. Running a new build using android studio fixes it. Works fine so far without hot reload or live reload.
I'm having this issue too. Async Storage is broken after a few hot module reload or menu button-> refresh.
If I swipe and kill the app and start again, everything works normally.
I think this won't be an issue in production because these two options is only available in development mode.
I'm having this problem in 0.51, #16905 didn't fix for me. Any other solutions?
+1 on 0.51
+1 on 0.50.3
This is a major show stopper! Need a solution!
Please guys, avoid +1
comments. Rather use the reactions feature. We all get notified but it doesn't add up to the conversation or opened pull requests.
It may also help if the icebox
tag changes to bug
or other with higher relevance.
I'd like to comment that I fixed what was happening at it was a dumb fault of mine, I'm on 0.50.3
I was using the promise.all to delete and save keys, but in one use case, a particular key was null and I hadn't noticed.
Async storage does not complain, but IOS dictionaries and android dbs do, since you can't save a key with a null value just like that.
Unfortunately, this is not an issue for me. I check for both key and value, they are all string.
Also, null key should raise an exception if it doesn’t.
Please help. This is also happening at my code
AsyncStorage.getItem('loggedInUser').then(item => {
debugger;
/*not here*/
}).catch(e => {
debugger;
/*and not here*/
});
Can anyone comment here if they are seeing this in production releases? I'm getting nervous about using this in our production app. I'm getting the same non-deterministic behavior, where it tends to work for a while on first load then just stops working.
I think the following are useful questions to diagnose this. I also provided what I personally am currently seeing
_Seen on release versions and debug. Tested with release version on Samsung Galaxy Tab A (Android 5.1)
Also consistently seen Emulators with Nexus 5x (API 25, Android 7) and Nexus 7 tablet (API 27, Android 7)_
_I have seen the behavior on both._
_Have tried in both Redux thunks and sagas_
_Rebuilding android (react-native run android) always fixes the issue for at least a while_
I use 'redux-persist'. I've tested on a physical device Android 6+ and encounter the same problem as on the emulators. It works but after some time spent around the application stops working normally. In my case, rehydate action never calls after this, the only one solution on the emulator just to kill and re-start.
I've just compiled a release APK, and it looks like this bug is still happening. My app is hanging when trying to store data. It appears to be successfully storing the data, but the promise isn't being fulfilled.
We have a login screen in our app, that tries to store a JWT using AsyncStorage, the login screen never completes, but if I close the app and launch it again, it manages to load the JWT and the main screen starts, so it looks like it manages to store the data, but can't complete the promise.
considering the ongoing issues with AsyncStorage on android (low size limit, not fulfilling promises in debug mode) I think the recommendation for the time being is to use fs storage adapters.
There are quite a few options, and there use is not limited to redux-persist (perhaps these packages should be renamed to something more generic like storage-adapter-X
The only limitation here is they do not have the merge and multi methods of AsyncStorage
Facing the same issue in react-native: 0.50.4
@jakewtaylor
I've just compiled a release APK, and it looks like this bug is still happening.
So this problem exists in production releases as well?!?
Up until I read your comment, I was under the impression this only impacts the dev environment and we'd be safe to produce production releases for the app market. If what you're saying is true, AsyncStrorage is no longer a valid solution for us and we need to bring in a separate product, like Realm or something.
Can you please confirm that this is what you meant?
@lancedolan I just switched to Realm, read this before switching: https://github.com/realm/realm-js/issues/491
UGH thanks for the heads up...
How does a RN dev do local storage in a way that works consistently and reliably in Dev and Production environments for both Android and IOS???
Does anyone have a failing test app or test case for this bug?
We have a team of testers and one of them reported he doesn’t retrieve a data saved from device storage and I hope it’s because of a bug in my code. If it’s related to the issue discussed here and happens in production, we are totally screwed. I’ll investigate it further.
It feels intermittent to me, which is usually the case when something is not intermittent and you simply haven't discovered the cause yet. When I have reliable steps to reproduce I'll post 'em up.
My experience debugging the issue was that the promise is simply never resolved and a breakpoint in the code in the promise callback is never hit. No errors, totally silent failure. I lost 2.5 hours last night chasing it around until I noticed that restarting the app ( just swipe it close from within emulator and restart) solves it.
In the meantime, I'm hiding the AsyncStorage usage behind an interface so I can jump ship the moment I find a reliable local storage solution if this isn't solved.
Seconded. Everything @lancedolan said I can repeat in my code.
I switched to SQLite using react-native-sqlite-2.
My initialization is described here: https://pastebin.com/sNFGFS4K
My functions are described here: https://pastebin.com/AubVsXik
It happens to me as well after a couple of hot reloads. The problem disappears if I kill and restart the app. My device is Pixel @ 8.1.0 under RN 0.52.5. This bug is so annoying.
+1
+1 on 0.53.0
+1 on 0.52.2
This is a pretty big bug and I'm surprised no one has looked into it after all these months.
I just did an update to 0.53 before finding this pretty serious bug.
Following on from https://github.com/facebook/react-native/issues/14101#issuecomment-345563563. I dumped the thread to find if I had any AsyncTask threads running/stalling. And happened to find this:
"AsyncTask #51@16284" prio=5 tid=0x2d61 nid=NA runnable
java.lang.Thread.State: RUNNABLE
at com.facebook.jni.HybridData$Destructor.deleteNative(HybridData.java:-1)
at com.facebook.jni.HybridData$Destructor.destruct(HybridData.java:73)
at com.facebook.jni.HybridData.resetNative(HybridData.java:39)
- locked <0x3fd4> (a com.facebook.jni.HybridData)
at com.facebook.react.bridge.CatalystInstanceImpl$1$1.run(CatalystInstanceImpl.java:349)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:762)
I have a feeling it's related to the com.facebook.jni.HybridData.resetNative()
method not completing properly for whatever reason. I don't have much familiarity with C to debug the issue further. Hopefully this issue can be fixed as soon as possible.
Tagging @cwdick and @alexeylang as they were involved in the https://github.com/facebook/react-native/commit/1c104310fbd76f3eb9e5ed66865f4671264ace8d change and might be able to shed some light on what might be going on.
Tagging @cwdick and @alexeylang as they were involved in the 1c10431 change and might be able to shed some light on what might be going on.
I don't think that change is relevant since it added only a few ReactMarker.logMarker() calls.
I don't think that change is relevant since it added only a few ReactMarker.logMarker() calls.
I was talking more about the change to wrap it in it's own AsynTask.execute
call. As that's where the AsyncTask thread executor seems to be stuck on.
I was talking more about the change to wrap it in it's own AsynTask.execute call.
It was wrapped even before that change (there two Runnable-s in that code).
GitHub doesn't show indentation changes well.
Aaah, I see what you mean now. Tagging @cwdick regarding this change https://github.com/facebook/react-native/commit/cf2ef84b16775e0e0eb53410e7e6e4ac66d05d03.
I'm aware the date for the commit is September 2017, which is after this issue was created. But my issue in particular seems to be related to this particular AsyncTask.execute
call or mHybridData.resetNative()
.
+1 on 0.53.0
Any recommended alternatives to AsyncStorage? - SQLite seems a bit heavy for only storing JWT..
@kccheung I also am testing on pixel and noticing it on pixel... I assumed this isn't device-dependent, but worth noting in case everybody here just happens to also be hitting this issue on a Pixel emulator.
Platforms and Alternatives
We've been at this bug for a while - it has been a show stopper for us - and this does seem to be Android device and platform independent (ie it occurs on everything). We have tried react-native-sql-lite2 and had the exact same issue. @hanselsen wondering if you can comment on your results using sql-lite2. We will be trying storage adapters soon and reporting on that, thanks to @rt2zz. Will report back on our success with that for anyone else trying alternatives.
Reproducing
I'm sorry to the maintainers that this issue is probably difficult to follow and no clear reproducible repo has been made. If we can make a reproducible example we will post it here, but it's a tough bug especially due to its indeterminate nature.
Narrowing the problem down....
My suspicion is that the bug is due to the way Android wakes up from being asleep, and that is somehow interfering with the storage mechanism call. We ONLY ever see this on login, and we grab the token literally every time we make a remote request. I think this clue will point to the solution
@smaccoun I switched to SQLite since my post. It is working like a charm. I am sing SQLite anyway, but I can imagine it feels like a bit overkill if you only want AsyncStorage.
same issue +1
RN version 0.52.1
same issue +1 TOO!!
RN version 0.54.0
My Emulator's Android Version Is 4.2, It seem not only on Android 7+
const StoreStorageKey = 'KeyStore'
export async function storePersist() {
try {
console.log('START STORE PERSIST') // printed
const pro = AsyncStorage.getItem(StoreStorageKey, function (err, result) {
console.log(err, result) // not printed
return result
})
console.log(pro) // print a promise
const snapshotStr = await pro
// below never run
console.log(snapshotStr, '=-=-0=-=-=-=-=-=-=-=-=-=')
if (snapshotStr) {
applySnapshot(Store, JSON.parse(snapshotStr))
}
} catch (e) {
console.log(e)
}
}
Having this issue in RN 0.53.3 on Android 7 (getItem
hangs when I reload the App), I made an implementation of the RN Settings API using Android SharedPreferences.
I just published react-native-cross-settings to NPM, please take a look, feedback is welcome.
NOTE: rn-cross-settings loads RN Settings on iOS, but I don't know if my implementation is full compatible with that API 'cause I don't have a Mac, know nothing about iOS, and the RN Docs about Settings
says nothing.
@aMarCruz I think your work is great! Can you make a pull request to fill in https://github.com/facebook/react-native/blob/26684cf3adf4094eb6c405d345a75bf8c7c0bf88/Libraries/Settings/Settings.android.js
I'm really sad that we have it unimplemented for a long time.
@ohtangza , I'm very busy these days, but next week I'll have some time to do that (with comments and tests). Thank you!
I have downgrade to 0.52.2, and it's works fine till now. Before the downgrade, the AsyncStorage will not return almost every time I reload.
@wd i tested on 0.52.2 and it still exists.
On first run during development async storage getitem works fine.
But hot reloads cause it to not work until killing / restarting.
I did some research, throughout the RN .execute is used rarely for GuardedAsyncTask, mostly .executeOnExecutor is used.
Any real reason for this?
I am seeing this issue in the latest: 0.54.2.
Everything works the first time after react-native run-android
but sometimes after hot-loading, AsyncStorage's getItem and setItem Promises never get fulfilled in either an error or success. I have not been able to figure out why it sometimes is working, then breaks until I react-native run-android
again.
Any thoughts on what to do about this @javache @mkonicek @nicklockwood ?
Thank you!
@hanselsen Hi Hans, sorry for the simple question. But I haven't has much experience with databases. How do you initialize your database ? Meaning what parameter do you pass to your 'export default function initializeDatabase(db: any)' function ?
In the example documentation for the library, they use this:
const db = SQLite.openDatabase('test.db', '1.0', '', 1);
Would that be appropriate? All I want is a database for key value pairs, just like AsyncStorage would have been. Token, name, user information... things like that.
@AliaMYH Here's my module. It contains 2 class: Database
& KeyValueStorage
.
````
import {Database} from "Storage.js"
// instance database
let Database = new Database("databaseName");
// execute query & get results
let rows = await database.execute("SELECT field1 FROM tableName WHERE field2 IN (?, ?)", value1, value2);
// iterate over rows
rows.forEach(row => console.log(row.field1));
import {KeyValueStorage} from "Storage.js"
// build storage
let storage = new KeyValueStorage("myNamespace");
// store keys & values
let errors = await storage.set({
key1 : "value1",
key2 : {
1 : "a",
// ...
}
});
// check errors
if (errors.key1)
console.warn(errors.key1);
// load datas
let results = await storage.get("key1", "key2");
// check error
if (!results.key1.error)
let value = results.key1.value;
````
@yairopro That's great thanks! So from what I understand of the code, and the example you have above. If i just want AsyncStorage behavior, I only need to deal with the KeyValueStorage class. Right? Just like in the second example above.
Have you tested it in a real app?
@AliaMYH Yes you just need use an instance of a KeyValueStorage.
I use those modules in my app. They work great. But I didn't use this file. What I mean is that this file contains a copy of my 2 original modules (they were originally in 2 separated files). I copied them in a single Gist for this issue, and quickly adapted them, because they originally had dependencies to other modules from my project. And I didn't tested them after copying.
But you're free to test and readapt them to work. Maybe you should make a repo. I didn't have time to do that. Sorry
@AliaMYH like this
constructor() {
this.db = SQLite.openDatabase({name: "my.sqlite"}, (db : Object) => {
console.log('OPEN DB', db.dbname);
}, err => {
console.log('ERROR DB');
console.error(err);
});
this.databaseInitialized = initializeDatabase(this.db);
}
Not sure this has anything to do with debugger or Android. I am consistently experiencing this on Android AND iOS, in debug mode with debugging turned off, as well as production builds.
+1.
It works fine on Android Emulator on development, but await AsyncStorage.getItem()
will hangs on Android Emulator after building a standalone apk.
maybe caused by expo
@AliaMYH please send me a PM for this. Please keep the thread clear for the actual issue, but I'm happy to help.
heads up for anyone still stuck on this, you can use an alternative adapter as a drop in replacement for AsyncStorage, such as https://github.com/leethree/redux-persist-fs-storage
I finally found a way to get out of this problem.
let storage= async () => await AsyncStorage.getItem("UserDetailsSave");
storage().then(result => {
console.log("result:", result)
}).catch(error=>{
console.log("Error:",error) });
@yashojha19 I think that is the initial problem.
Sometimes I cannot access storage if the app is reloaded, so.. I need to compile the app again.
https://github.com/sunnylqm/react-native-storage/issues/159
Screenshot:
same problem
I was already using react-native-fs for my project. so, I used it to store a file containing JSON data, and fetched back on program starts. I know its not the right way. but its working perfectly, and I am really scared of using AsyncStorage now.
@yashojha19 i'm gonna fix this stuff in the same way.
I have fixed the issue with an additional method on my component with async await
async getItemFromAsyncStorage(key){
try{
let value = await AsyncStorage.getItem(key);
return value.token;
}
catch(e){
// handle error
}
}
This issue is not resolved even a few months later... I have the same issue...
@Clowning what version are you running? This seems fixed to me on react-native 0.54.4. Although my repro was never very good so I'm not 100% sure.
@coffenbacher Since this issue is continued over several versions, I think our community is strong confirmation on it. Do you have any idea which pull request has resolved this issue?
@coffenbacher I'm using react-native '0.54.3' but it's a general issue I think !
I change to Expo SecureStore and everything working fine.
Same problem here react-native '0.54.2'
You don’t need to rebuild the app everytime this happens, instead you can
longpress > App Info > Force Stop
and the asyncStorage will behave again next time you launch.
Got the same issue although I was only able to replicate the problem on Android rather than iOS. RN 0.53.0 running on a samsung galaxy J3 with android 5.1.1.
On iOS I'm running on an iPhone X and not seen any issue. All my tests and all issues have thus far been reproducible on native devices. Have not tried simulators.
I still see this issue whenever running/developing RN apps in dev mode on any Android simulator/device 🙁It significantly slows down speed of development because you lose momentum every time you have to kill the app and re-run it. We have to fix this!
same , RN 0.53.0 running on android
Seeing this issue on 0.55.2 on Android
Hi gays
I have this problem too and created very simple package
yarn add rn-async-storage
react-native link rn-async-storage
replace import
import {AsyncStorage} from 'react-native'
to
import {AsyncStorage} from 'rn-async-storage'
sorry but only works on android, on ios work all method because I use AsyncStorage from react-native for ios
clear()
on ios work all method because I use AsyncStorage from react-native for ios
If you need other methods from AsynStorage let me know
https://www.npmjs.com/package/rn-async-storage
https://github.com/gadfil/rn-async-storage
Is there any PR to fix this issue on React Native itself?
I use shared preference in android
This is a temporary solution
I hope AsyncStorage will be fix in the next release of react-native, but now this solution helped me in my project
Yep, I'm using react-native-default-preference
now to workaround the problem, but it's annoying to have such a clear bug in the core library...
@gadfil thank you! your package save my time and nerves. really simple and fast solution.
@gadfil your module is not using async SQLite but the more limited SharedPreferences.
It is doing something like react-native-cross-settings but using the global getPreferences
instead getSharedPreferences
and has no promise rejection in the setItem
and clear
methods.
Anyway is a good attempt. I still hope that the RN team will give us a solution.
@aMarCruz you are right
Add rejection in the setItem
and clear
methods
I hope so too AsyncStorage in react-native will be fix in the near future
And that's why I use interface AsyncStorage
As soon as AsyncStorage will be fixed I'll back to use AsyncStorage
Add code to AndroidManifest.xml file
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
@xiaoyu311 You are 100% wrong. AsyncStorage uses an SQLite DB under the hood which doesn't require any permission.
I went back to a 6.0 emulator and still found the same issue. So this is not just a 7+ problem
Confirming this problem still exists.
Only seeing it on Android.
Still persists, Android 6, API 23, emulator.
+1
Is this actually genuinely broken in RN core, and has been since May 2017, and the only solution is to use a third party library that replaces it?
@jsdevel I would say yes. It might take a long time to recover the credibility of this API again for the existing developers, I guess.
+1
I'm seeing this issue on RN 0.55.3
Soon... we might have a one-year anniversary... sad...
This bug is really annoying because every time it happens I have to re-run the app again via the terminal, then the error will go away. But you can never tell when it will re-appear again because it seems to happen randomly.
Edit: I'm on RN 0.52.0
+1
annnnd there goes the one-year anniversary of this bug.
Since this issue is just polluted by useless comments, no need to keep it unlocked.
If you are looking for solutions, there are snippets proposed in the past comments, and two open PRs that are being discussed:
For those following along, #18522 has been approved and we're working on getting it merged.
Most helpful comment
I'm seeing this too. The promise returned by
AsyncStorage.getItem()
just never resolves on Android. iOS is fine. I'm on RN 0.50RC.