Mael Fosso
Mael Fosso

Reputation: 400

ClassNotFoundException when unmarshalling: io.realm.NeedRealmProxy$$Parcelable

I got this error when running this snippet of code from a fragment HomeFragment

public void onTaskClick(View view, Need need, int position) {
    Log.d(TAG, "onTaskClick() - " + need.toString());

    Intent intent = new Intent(getActivity(), TaskDetailsActivity.class);

    Bundle bundle = new Bundle();
    bundle.putParcelable(TaskDetailsActivity.EXTRA_OBJ_NEED, Parcels.wrap(need));

    startActivity(intent, bundle);
}

Here is Need.java

@Parcel(implementations = {NeedRealmProxy.class}, value = Parcel.Serialization.FIELD, analyze = { Need.class })
public class Need extends RealmObject implements Serializable {

    @PrimaryKey
    @SerializedName("_id")
    private String id;

    @SerializedName("created")
    private Date created;

    @SerializedName("status")
    private String status;

    @SerializedName("fees")
    float fees;

    @SerializedName("user")
    private User user;

    @ParcelPropertyConverter(RealmListParcelConverter.class)
    @SerializedName("places")
    private RealmList<Place> places;

    @SerializedName("user_location")
    private Place userLocation;

    @ParcelPropertyConverter(RealmListParcelConverter.class)
    @SerializedName("items_ordered")
    private RealmList<ItemOrdered> itemsOrdered;

    @ParcelPropertyConverter(RealmListParcelConverter.class)
    @SerializedName("movings")
    private RealmList<Moving> movings;

    @ParcelPropertyConverter(RealmListParcelConverter.class)
    @SerializedName("messages")
    private RealmList<Message> messages;

    @SerializedName("run")
    private Run run;


    public Need() {}

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public List<Place> getPlaces() {
        return places;
    }

    public List<ItemOrdered> getItemsOrdered() {
        return itemsOrdered;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Double getAmount() {
        double p = 0;
        for (ItemOrdered e: itemsOrdered) {
            if (e.getItem().getPrice() != null) {
                p += e.getItem().getPrice() * e.getQuantity();
            }
        }

        return p;
    }

    public Place getUserLocation() {
        return userLocation;
    }

    public void setUserLocation(Place userLocation) {
        this.userLocation = userLocation;
    }

    public Date getCreated() {
        return created;
    }

    public String getCreatedFormatted() {
        SimpleDateFormat format = new SimpleDateFormat("MMM dd, HH:mm");

        return format.format(created);
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public String getStatus() {
        return status;
    }

    public List<Message> getMessages() {
        return messages;
    }

    public Run getRun() {
        return this.run;
    }

    public List<Moving> getMovings() {
        return movings;
    }

    public void setMovings(RealmList<Moving> movings) {
        this.movings = movings;
    }

    public float getFees() {
        return fees;
    }

    public void setFees(float fees) {
        this.fees = fees;
    }

    public void setPlaces(RealmList<Place> places) {
        this.places = places;
    }

    public void setItemsOrdered(RealmList<ItemOrdered> itemsOrdered) {
        this.itemsOrdered = itemsOrdered;
    }

    public void setMessages(RealmList<Message> messages) {
        this.messages = messages;
    }

    @Override
    public String toString() {
        return "Need{" +
                "id= '" + id + '\'' +
                ", movings='" + movings.size() + '\'' +
                ", places=" + places.size() +
                ", itemsOrdered=" + itemsOrdered.size() +
                ", userLocation=" + userLocation.getLng() + "," + userLocation.getLat() +
                ", user=" + user +
                '}';
    }
}

Here is RealmListParcelConverter.java

public class RealmListParcelConverter implements
        TypeRangeParcelConverter<RealmList<? extends RealmObject>, RealmList<? extends RealmObject>> {
    private static final int NULL = -1;

    @Override
    public void toParcel(RealmList<? extends RealmObject> input, android.os.Parcel parcel) {
        parcel.writeInt(input == null ? NULL : input.size());
        if (input != null) {
            for (RealmObject item : input) {
                parcel.writeParcelable(Parcels.wrap(item), 0);
            }
        }
    }

    @Override
    public RealmList fromParcel(android.os.Parcel parcel) {
        int size = parcel.readInt();
        RealmList list = new RealmList();
        for (int i=0; i<size; i++) {
            Parcelable parcelable = parcel.readParcelable(getClass().getClassLoader());
            list.add((RealmObject) Parcels.unwrap(parcelable));
        }
        return list;
    }
}

Error

android.os.BadParcelableException: ClassNotFoundException when unmarshalling: io.realm.NeedRealmProxy$$Parcelable at android.os.Parcel.readException(Parcel.java:1427) at android.os.Parcel.readException(Parcel.java:1379) at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:1761) at android.app.Instrumentation.execStartActivity(Instrumentation.java:1411) at android.app.Activity.startActivityForResult(Activity.java:3351) at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:50) at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:79) at android.support.v4.app.ActivityCompatJB.startActivityForResult(ActivityCompatJB.java:30) at android.support.v4.app.ActivityCompat.startActivityForResult(ActivityCompat.java:146) at android.support.v4.app.FragmentActivity.startActivityFromFragment(FragmentActivity.java:932) at android.support.v4.app.FragmentActivity$HostCallbacks.onStartActivityFromFragment(FragmentActivity.java:1047) at android.support.v4.app.Fragment.startActivity(Fragment.java:940) at com.nkapsi.ui.fragment.HomeFragment.onTaskClick(HomeFragment.java:201)

Upvotes: 2

Views: 545

Answers (3)

Barno
Barno

Reputation: 786

RealmObject can't be Serializable. So you will not be able to pass any RealmObject using put extra. In that case you should pass the id of the RealmObject. And in the target Activity you should query for the RealmObject using this id. As @Eric Maxwell answered.

Upvotes: 0

Eric Maxwell
Eric Maxwell

Reputation: 76

You should pass the id instead and pull the object out by id on the other side.

Something like:

public void onTaskClick(View view, Need need, int position) {
    Log.d(TAG, "onTaskClick() - " + need.toString());

    Intent intent = new Intent(getActivity(), TaskDetailsActivity.class);
    intent.putExtra("need_id", need.getId());
    startActivity(intent);
}

Then in the Activity receiving the id, get the object back out.

// in onCreate(), onHandleIntent(), etc.
// get the needId back out.
String needId = intent.getStringExtra("need_id");

// get the object out by id. 
realm.where(Need.class).equalTo("id", needId).findFirst();

// Lookup by PK is super fast, but if you want you can always use 
realm.where(Need.class).equalTo("id", needId).findFirstAsync();
// This will make this microsecond lookup happen on a background thread
// and return the object back to you on your main thread, but is 
// probably overkill for a single object.

More on this (https://realm.io/docs/java/latest/#intents)

Upvotes: 3

EpicPandaForce
EpicPandaForce

Reputation: 81529

Do

@Parcel(value = Parcel.Serialization.FIELD, analyze = { Need.class })

and

bundle.putParcelable(TaskDetailsActivity.EXTRA_OBJ_NEED, Parcels.wrap(realm.copyFromRealm(need)));

P.S. typically you just need to send the primary key of the object though, not the whole object.



But based on the realm-java issues, apparently you need following proguard config

-keepnames public class * extends io.realm.RealmObject

Upvotes: 0

Related Questions