BackendlessUser as a Parcel

Hi!

After some days looking for a solution, I can’t get it working, so here I am.
I’m desperately trying to pass a BackendlessUser as a Parcel from on Activity to another in Android.

Here is my structure:
I have a “Request” class, any user in the app can make a request, and they can make the request for a friend too. So I thought the easiest way to put it into code was to have a relation with the BackendlessUser class.

My request class looks a bit like that:

public class Request implements Parcelable {
    private BackendlessUser user;


    public BackendlessUser getUser() {
        return user;
    }


    protected Request(Parcel in) {
        user = (BackendlessUser) in.readValue(BackendlessUser.class.getClassLoader());
    }


    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeValue(user);
    }
}

BUT, it doesn’t work! I thought that since BackendlessUser implements Serializable (which is bad, it should be Parcelable), it would work, but it doesn’t.

In face, I even tried to simply pass a user as a serializable object in an Intent, aaaand… not better.

Intent intent = new Intent(MainActivity.this, DestinationActivity.class);
intent.putExtra("user", Backendless.UserService.CurrentUser());
startActivity(intent);

Here is what I get:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.vetasoft.backendlesstest, PID: 7486
    java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = com.backendless.BackendlessUser)
        at android.os.Parcel.writeSerializable(Parcel.java:1394)
        at android.os.Parcel.writeValue(Parcel.java:1341)
        at android.os.Parcel.writeArrayMapInternal(Parcel.java:644)
        at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1313)
        at android.os.Bundle.writeToParcel(Bundle.java:1034)
        at android.os.Parcel.writeBundle(Parcel.java:669)
        at android.content.Intent.writeToParcel(Intent.java:7511)
        at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:2440)
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1496)
        at android.app.Activity.startActivityForResult(Activity.java:3843)
        at android.app.Activity.startActivityForResult(Activity.java:3804)
        at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:843)
        at android.app.Activity.startActivity(Activity.java:4114)
        at android.app.Activity.startActivity(Activity.java:4082)
        at com.vetasoft.backendlesstest.MainActivity$1$1.handleResponse(MainActivity.java:34)
        at com.vetasoft.backendlesstest.MainActivity$1$1.handleResponse(MainActivity.java:27)
        at com.backendless.UserService$8.handleResponse(UserService.java:764)
        at com.backendless.UserService$8.handleResponse(UserService.java:749)
        at com.backendless.async.message.AsyncMessage$ResponseHandler.handle(AsyncMessage.java:64)
        at com.backendless.async.message.AsyncMessage.handleCallback(AsyncMessage.java:41)
        at com.backendless.core.AndroidCarrier$1.handleMessage(AndroidCarrier.java:37)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5300)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)
     Caused by: java.io.NotSerializableException: java.lang.Object
        at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1344)
        at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1651)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1497)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1461)
        at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:959)
        at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:360)
        at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1054)
        at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1384)
        at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1651)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1497)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1461)
        at android.os.Parcel.writeSerializable(Parcel.java:1389)
        at android.os.Parcel.writeValue(Parcel.java:1341) 
        at android.os.Parcel.writeArrayMapInternal(Parcel.java:644) 
        at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1313) 
        at android.os.Bundle.writeToParcel(Bundle.java:1034) 
        at android.os.Parcel.writeBundle(Parcel.java:669) 
        at android.content.Intent.writeToParcel(Intent.java:7511) 
        at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:2440) 
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1496) 
        at android.app.Activity.startActivityForResult(Activity.java:3843) 
        at android.app.Activity.startActivityForResult(Activity.java:3804) 
        at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:843) 
        at android.app.Activity.startActivity(Activity.java:4114) 
        at android.app.Activity.startActivity(Activity.java:4082) 
        at com.vetasoft.backendlesstest.MainActivity$1$1.handleResponse(MainActivity.java:34) 
        at com.vetasoft.backendlesstest.MainActivity$1$1.handleResponse(MainActivity.java:27) 
        at com.backendless.UserService$8.handleResponse(UserService.java:764) 
        at com.backendless.UserService$8.handleResponse(UserService.java:749) 
        at com.backendless.async.message.AsyncMessage$ResponseHandler.handle(AsyncMessage.java:64) 
        at com.backendless.async.message.AsyncMessage.handleCallback(AsyncMessage.java:41) 
        at com.backendless.core.AndroidCarrier$1.handleMessage(AndroidCarrier.java:37) 
        at android.os.Handler.dispatchMessage(Handler.java:98) 
        at android.os.Looper.loop(Looper.java:135) 
        at android.app.ActivityThread.main(ActivityThread.java:5300) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:372) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699) 

Any ideas how I should pass a BackendlessUser from one Activity to another?

Also, using the ownerId is NOT what I need, since the requests are displayed in a List, I need to have every user available (since they are in autoload, it should work).

Hi Dylan,

How about using the getProperties() method on BackendlessUser to get the data it contains and transfer that between the activities? You can easily transfer the properties out of and into BackendlessUser instance:
https://backendless.com/documentation/users/android/users_user_properties.htm

Regards,
Mark

Hi,

HashMap and Map aren’t parcelable either. If they contained only primitive values, I could use writeSerializable and write user.getProperties. But my users contains some relations to other objects, that are Parcelable, but not Serializable.

Here is an example:
http://support.backendless.com/public/attachments/b2f0651173c485f5e8f8eb61697474c0.png</img>

In the Request class, I try to write the parcel like this:

public void writeToParcel(Parcel dest, int flags) {
	dest.writeSerializable(user.getProperties());
}

But since Address, in the user, is Parcelable, and not Serializable, I get a NotSerializableException:

Caused by: java.io.NotSerializableException: com.vetasoft.mapass.model.Address

Alternatively, I could write every single property of the user in the Parcel, and read them one by one, but this is not really Developer-friendly, and I would have to edit every class of my Model that has a reference to BackendlessUser if I want to add a single property to BackendlessUser…

Why parcel/serializing when this can be done with a Singleton?

Have a Singleton, set your value to the singleton in activity a, retrieve it in activity b, done.

This is not how you’re supposed to pass data between activities.
If the app gets killed by the system, the Singleton will loose its value, whereas I can store a parcelable in case of memory warning.

Dylan,

Address is your class, isn’t it? Why can’t you declare it Parcelable to avoid the NonSerializableException?

Regards,
Mark

It is Parcelable, but not Serializable =/

Since it is a class you wrote and control, can you make it both? Parcelable and Serializable?

I understand the issue with the Singleton vs app lifecycle.

Another option could be to serialize your object into a JSON string (with Gson/Logansquare, sth. else) and put this into your intent as stringExtra. Then in your 2nd activity, parse it back into a class object.

@Mark I think this is what I’m going to do for now. But it is not a good solution on Android. Parcelable was made especially because Serializable is not optimized. I suggest you talk to the Android Development team at Backendless to see if they could eventually make an Android-Specific Library which implement Parcelable instead of Serializable.

@Jens It may be a solution, but I don’t know if Gson can serialize a object like BackendlessUser since all its properties are stored as “Object” in an HashMap.

TL;DR
I made my model implements Serializable AND Parcelable.
But I think i’ll switch to the REST api with Retrofit.

ps: I don’t know how to change the topic from “Need Answer” to “Answered”, the Edit option is not on the first message. Can you switch it for me?

Hi Dylan,

The design constraint we have is keeping the SDK “neutral”, meaning it should work both for Android and Java. As a result, any bindings to Android which make core classes unavailable for Java are not desirable.

Regards,
Mark
p.s. I changes the status to Answered.