Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Making any call to 'ParseUser.saveInBackground()' on the UI Thread freezes app #993

Open
bstillitano opened this issue Nov 25, 2019 · 12 comments

Comments

@bstillitano
Copy link

I have noticed that no matter what, even on a fresh app install, if you call `ParseUser.getCurrentUser().saveInBackground()' on a UI Thread the app will hang. The example I used was calling the function after updating a user value after toggling a Switch component:

fun setAccountPrivacy(on: Boolean) {
    ParseUser.getCurrentUser().put("privateAccount", on)
    ParseUser.getCurrentUser().saveInBackground()
}

I've written a basic custom activity to prove my hypothesis. Starting an Activity of this type will cause the app to hang and leave a blank screen as can be seen by simulator screenshot attached. Activity is as follows:

import androidx.appcompat.app.AppCompatActivity
import com.parse.ParseUser

open class CustomActivity : AppCompatActivity() {
    override fun onResume() {
        super.onResume()

        //Save Parse User
        ParseUser.getCurrentUser().saveInBackground()
    }
}

After Running
Screenshot_1574686165

If commenting out the saveInBackground() function
Screenshot_1574686306

@Jawnnypoo
Copy link
Member

I believe ParseUser.getCurrentUser() can be an expensive operation. It is best to instead create a task/background operation that calls getCurrentUser and then saves, all in the background.

@bstillitano
Copy link
Author

@Jawnnypoo thanks for the suggestion as well as taking the time to comment and help. I’ll give this a shot this evening and let you know how I go and what a tried.

@bstillitano
Copy link
Author

bstillitano commented Dec 4, 2019

@Jawnnypoo so I've mucked around with this and it hasn't resolved the issue. I did

AsyncTask.execute {
    ParseUser.getCurrentUser().saveInBackground()
}

I still end up with the same results. After some testing, the ParseUser.getCurrentUser() on its own doesn't seem to be causing the issue. It only hangs once I add the saveInBackground(). I'm at a real loss as this is causing me massive issues in getting a release out.

@Jawnnypoo
Copy link
Member

Did you try ParseUser.getCurrentUser().save() since you are already on a background thread with the AsyncTask?

@ramiro-ciocca
Copy link

I had a lot of similar issues saving objects with the Android SDK.
What I have learnt is that when the objects are complex, with nested references (pointers), then the app hangs on save no matter what (saveInBackground, save with AsyncTask, saveEventually...)
In the logcat I see an endless loope of "Garbage collecting blah blah".
The only workaround I found to keep my app working was to wirte cloud functions for the save, then from the Android cliente just call ParseCloud.callFunction... with a Map of properties as params, then save the object in the server, not in the android client.
I think all the save objects part of the android sdk is faulty and buggy especially in memory managment.

@bstillitano
Copy link
Author

@ramiro-ciocca you may be onto something with that, alot of my objects are complex with pointers to different objects. This shouldn't have to be worked-around on the server side though. This is a critical bug that should be looked into immediately if this is truly the case.

@ramiro-ciocca
Copy link

@bstillitano, could you check if you see a loop of "garbage collecting" in the logcat when your app hangs?
Using the debugger I have verified that the culprit of this hangs is a recursive method from ParseObject class, part of the save methods. This method recursivelly traverse all the nested objects in a very inefficient way, looking for dirty properties on every object, on ever property, on all the chain of pointers, and it is too bad if you just want to save the plain surface-father object.
I think one solution whould be to implement "cascadeSave: false" like in the JS SDK.
I dont have the time nor the knowledge to implement it, but luckily there are people in this comunity that runs companies based on Parse so I think they should implement it.

@ramiro-ciocca
Copy link

I forgot something very important. All the issues with save disappear if you disable th local data store.
So it is clearly a LDS related issue, that traverse all local cached data when you save looking for dirty objects, and it does it very slowly so the app looks hanged up. If you wait long enough it will finish it job and the app will come back alive, but it can take a lot of minutes depending on your local cached data and the complexity of your objects.

@bstillitano
Copy link
Author

@ramiro-ciocca I've changed my init call so that it does not enable the LDS and it would appear that this does fix the issue.

I am fine to keep using this workaround as I don't pin any data in my app and don't mind assuming that my users will always have an internet connection but this is a massive issue for devs relying on LDS for offline data storage. It means that they will need to integrate yet another SDK like realm in order to have any offline functionality.

@ramiro-ciocca
Copy link

Yes, so we are 100% sure that it is a LDS related issue, and I have verified that the issue is in a recursive method inside save methods from ParseObject class, that recursivelly traverse through all the pinned objects before saving, looking for dirty properties. It is very inefficient since it takes minutes to traverse all the structure, depending on your structure of course, but it is enough to have some pointers to hang all the app.
cascadeSave flase should be a fix, and in the meantime porting code to cloud is the working workaround. This have multiple disadvantages like fetching the objects you need to save, because the cloud functions dont accept parse objects as parameters. Let alone rewrite all your save code from android to javascript.

@bstillitano
Copy link
Author

I can confirm that the traversal is also happening on my end. I think a cascade type value should be defaulted to false. If I am calling save on an object, I don't necessarily expect that it will save the children of that object.

@ramiro-ciocca
Copy link

ramiro-ciocca commented Feb 19, 2020

I'm still having problems when saving complex objects, can anyone implemente "cascadeSave=false" like parameter for save, please?
Something that just prevent the traverse method inside save method in ParseObject?
Thanks!
@mtrezza @flovilmart @Jawnnypoo @davimacedo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants