0

I'm using Firebase to store my data, and Master/Detail Activity to show a list of documents and when the user clicks on any of them Detail Activity should show the data of that document.

The problem is I'm unable to send DocumentReference (class provided by Firebase) to DetailActivity with intent.putExtra() as DocumentReference is not Serializable.

Here is my relevant code:

ListActivity.java

OnClickListener for list item, inside onBindViewHolder on my RecyclerView

final View.OnClickListener mOnClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Expense item = (Expense) view.getTag();
        if (item != null) {
            Context context = view.getContext();
            Intent intent = new Intent(context, DetailActivity.class);
            intent.putExtra(DetailFragment.ARG_ITEM_ID, item);
            context.startActivity(intent);
        }
        else {
            Log.e(TAG, "item is null");
        }
    }
};

DetailFragment.java

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (getArguments().containsKey(ARG_ITEM_ID)) {
        Log.d(TAG, getArguments().getSerializable(ARG_ITEM_ID).toString());
        Expense item = (Expense) getArguments().getSerializable(ARG_ITEM_ID);
        Log.d(TAG, "Received="+item.toString());
    }
}

Expense.java

public class Expense implements Serializable {

    public DocumentReference id;
    private String TAG = "Expense";

    private Timestamp timestamp;
    private float amount;
    private String description;

    // Do not remove this, it is required by FirebaseFirestore
    public Expense() { }

    public Expense(float amount, String description, Date timestamp) {
        this.timestamp = (timestamp == null) ? Timestamp.now() : new Timestamp(timestamp);
        this.amount = amount;
        this.description = description;
    }

    public float getAmount() {
        return amount;
    }

    public String getDescription() { return description; }

    public Timestamp getTimestamp() {
        return timestamp;
    }

    public DocumentReference getId() { return id; }

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

    public String toString() {
        Map<String, Object> objectMap = new HashMap<>();
        objectMap.put("timestamp", this.timestamp);
        objectMap.put("amount", this.amount);
        objectMap.put("description", this.description);
        return objectMap.toString();
    }
}

Logcat of error

com.example.expenditure E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.expenditure, PID: 9373
    java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = com.example.expenditure.NewExpense.Expense)
        at android.os.Parcel.writeSerializable(Parcel.java:1833)
        at android.os.Parcel.writeValue(Parcel.java:1780)
        at android.os.Parcel.writeArrayMapInternal(Parcel.java:928)
        at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1584)
        at android.os.Bundle.writeToParcel(Bundle.java:1253)
        at android.os.Parcel.writeBundle(Parcel.java:997)
        at android.os.Parcel.writeValue(Parcel.java:1698)
        at android.os.Parcel.writeArrayMapInternal(Parcel.java:928)
        at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1584)
        at android.os.Bundle.writeToParcel(Bundle.java:1253)
        at android.os.Parcel.writeBundle(Parcel.java:997)
        at android.content.Intent.writeToParcel(Intent.java:10495)
        at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:3823)
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1705)
        at android.app.Activity.startActivityForResult(Activity.java:5192)
        at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:767)
        at android.app.Activity.startActivityForResult(Activity.java:5150)
        at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:754)
        at android.app.Activity.startActivity(Activity.java:5521)
        at android.app.Activity.startActivity(Activity.java:5489)
        at com.example.expenditure.ExpenditureListActivity$1.onClick(ExpenditureListActivity.java:114)
        at android.view.View.performClick(View.java:7125)
        at android.view.View.performClickInternal(View.java:7102)
        at android.view.View.access$3500(View.java:801)
        at android.view.View$PerformClick.run(View.java:27336)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
     Caused by: java.io.NotSerializableException: com.google.firebase.firestore.DocumentReference
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1240)
        at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1604)
        at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1565)
        at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1488)
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1234)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:354)
Nikhil Wagh
  • 1,376
  • 1
  • 24
  • 44
  • Hi Nikhil! I marked this question as a duplicate as it already has an answer. So please check the duplicate to see how you can solve this. – Alex Mamo May 11 '20 at 07:48

1 Answers1

1

Instead of passing the DocumentReference pass the names of the Collection and the Document, and reconstruct the DocumentReference in the DetailActivity:

This:

public class Expense implements Serializable {

    public DocumentReference id;
    private String TAG = "Expense";

    private Timestamp timestamp;
    private float amount;
    private String description;
    .......

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

Becomes:

public class Expense implements Serializable {

    //add these instead of DocumentReference
    public String CollectionName;
    public String DocumentName;

    private String TAG = "Expense";

    private Timestamp timestamp;
    private float amount;
    private String description;
    ........
    .......

    public void setCollectionName(String name) { this.CollectionName= name; }
    public void setDocumentName(String name) { this.DocumentName= name; }   ......

Before you send the item in intent:

    .............
    Context context = view.getContext();
    Intent intent = new Intent(context, DetailActivity.class);
    //add these
    item.setCollectionName("YOUR_COLLECTION_NAME");
    item.setDocumentName("YOUR_DOCUMENT_NAME");

    intent.putExtra(DetailFragment.ARG_ITEM_ID, item);
    context.startActivity(intent); 
    ...............

In the DetailFragment.java:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (getArguments().containsKey(ARG_ITEM_ID)) {
        Log.d(TAG, getArguments().getSerializable(ARG_ITEM_ID).toString());
        Expense item = (Expense) getArguments().getSerializable(ARG_ITEM_ID);

        //reconstruct the document reference
        FirebaseFirestore db = FirebaseFirestore.getInstance();
        DocumentReference docRef = db.collection(item.CollectionName).document(item.DocumentName);
        Log.d(TAG, "Received="+item.toString());
    }
}
Hasan Bou Taam
  • 4,017
  • 2
  • 12
  • 22