Wonton Wonton - 16 days ago 5
Android Question

Android switch from Parse to Parse Server crashes

I'm migrating my Android and iOS app from Parse.com to Parse Server. First I'm doing this migration with a test app to be sure everything is ok.
With iOS there has been no problem but with Android the updated app crashes each time the user enters in the app.

This is the Android code updated:

public static void initParse(Application app) {
ctxt = app.getApplicationContext();
Parse.enableLocalDatastore(app);
// Old version
//Parse.initialize(app, "<my app id>", "<my client key>");
// New version
Parse.initialize(new Parse.Configuration.Builder(ctxt)
.applicationId("<my app id>")
.clientKey(null)
.server("https://<my new server>/parse/")
.build()
);
ParseUser.enableRevocableSessionInBackground();
}


The crash returns a "com.parse.ParseException: java.lang.IllegalStateException: unable to encode an association with an unsaved ParseObject", and taking into account what I've read in Stackoverflow, this is because ParseUser.getCurrentUser() returns null (despite the user is logged in) and Parse methods fail.

In fact, if I take this same code, uncomment the old version of Parse.initialize, comment the new version of Parse.initialize, compile and launch the app, this is launched without problems and the user can use it properly.

But again, if I comment the old version of Parse.initialize, uncomment the new version of Parse.initialize, compile and launch the app, this crashes inmediately because ParseUser.getCurrentUser() returns null and Parse methods fail.

What am I missing here? Should I force my users to login again? This seems to me a bad UX, and anyway, in iOS I have no problems with the new version, what is the difference between both platforms?

EDIT 1:

Following Robert Rowntree advice I've changed the initialization to this:

public static void initParse(Application app) {
ctxt = app.getApplicationContext();
Parse.enableLocalDatastore(app);
// Old version
//Parse.initialize(app, "<my app id>", "<my client key>");
// New version
Parse.initialize(new Parse.Configuration.Builder(ctxt)
.applicationId("<my app id>")
.clientKey("<my client key>")
.server("https://<my new server>/parse/")
.build()
);
//Parse.setLogLevel(Parse.LOG_LEVEL_DEBUG);
Parse.setLogLevel(Parse.LOG_LEVEL_VERBOSE);
ParseUser.enableRevocableSessionInBackground();
}


Besides this I've checked that my Parse version is the last available, I have this in my gradle file:

compile 'com.parse.bolts:bolts-android:1.+'
compile 'com.parse:parse-android:1.+'


And the result is the same, the app crashes with "com.parse.ParseException: java.lang.IllegalStateException: unable to encode an association with an unsaved ParseObject" the first call I make to Parse.
Besides this, the unique log I can see related to parse is one related to GCM token, nothing else.

EDIT 2:

I've tried another thing, uninstall the app with the old initialization and install it with the new initialization and as I guessed the new version is now working.

But, of course this is not a solution to me, I can not tell my users to uninstall the app ans install it again.

But this is a hint: there is no problem with the new initialization but with how the old Parse "reacts" when opening the app with the new Parse Server, there must be any inconsistency in getCurrentUser or something like that.

Answer

Can you try initializing like this:

Parse.initialize(new Parse.Configuration.Builder(this)
                        .applicationId("APP_ID")
                        .clientKey("CLIENT_KEY")
                        .server("https://SERVER_URL/parse/") // The trailing slash is important.
                        .enableLocalDataStore()
                        .build()
                );

notice the

.enableLocalDataStore()

is in the initilization. Remove this:

Parse.enableLocalDatastore(app);