Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are Custom Objects Passed by value or passed by Reference in Fragments and Activities.?

hello Java and Android Experts. I am having a Problem. I am making a XMPP based chat Application. There are a few things that are confusing me.

I have a class named Room_Structure which implements Serializable. This class has an object named currentRoom.

If i am passing currentroom object between two fragments by putting it in a bundle its working fine and surprisingly it is passed by reference. i dont know why is that. It shouldnt behave like this. btw i am using Android Support library?

But if i am passing that currentRoom object between Activities using a bundle and putting that bundle in an intent then i am getting a crash whenever i try to start a new activity using that intent.

For More Description Here is the Code

public class Room_Structure implements Serializable {


    private static final long serialVersionUID = 1L;
    private String Rname;
    private ArrayList<Message_Pattern> msg_list;
    private MultiUserChat XmppSession;
    private boolean Background;
    private boolean Modified;
    private boolean Destroyed;
}

The above class has constructors as well as getter and setters.

Now Here is What i am doing:

Consider That currentRoom object has already been populated and here is how i am Passing it to Fragment

    Bundle b = new Bundle();
    b.putSerializable("RoomObject", currentRoom);
    Fragment_Chat newChat = new Fragment_Chat();
    newChat.setArguments(b);
    FragmentManager fm = getChildFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.fl_chatFragment, newChat);
    ft.addToBackStack(null);
    ft.commit();

retrieving it from Fragment_Chat OnActivityCreated() method like this

Bundle extras = getArguments();
Room_Structure recievedRoom = (Room_Structure) extras.getSerializable("RoomObject");

Now this above code is working Just fine for Fragments. the only problem is that the object's reference is passed to the new fragment. Which is not how it should really behave. It should just send value not reference.

Here is how i know that objects are passed by reference

Sending Object : com.software.chat.Classes.Room_Structure@425585e8
Recieved Object: com.software.chat.Classes.Room_Structure@425585e8

both have same reference or Address. Checked it out during Debugging

Now i cant replicate this behavior in Activities

I have an Activity which contains a ExpandibleListView. I have implemented the adapter for this Expandiblelistview by extending it from BaseExpandableListAdapter. This adapter class name is Websites_ListAdapter.java. It is also passed activity's context in its constructor. And i have made a layout clickable in the list. And i want to start an activity when that is clicked. please Don't ask why i did this its a long story. I am Sending this object from that Websites_ListAdapter like this

Intent i=new Intent(ActivityContext, ChatScreen.class);
    Bundle b = new Bundle();
    b.putSerializable("RoomObject", currentRoom);
    i.putExtras(b);
    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    ActivityContext.startActivity(i);

But i get this error in Logcat This time when i call ActivityContext.startActivity(i)

04-25 15:38:07.474: E/AndroidRuntime(10250): FATAL EXCEPTION: main
04-25 15:38:07.474: E/AndroidRuntime(10250): java.lang.RuntimeException: Parcelable encountered IOException writing 

serializable object (name = com.software.chat.Classes.Room_Structure)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.os.Parcel.writeSerializable(Parcel.java:1279)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.os.Parcel.writeValue(Parcel.java:1233)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.os.Parcel.writeMapInternal(Parcel.java:591)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.os.Bundle.writeToParcel(Bundle.java:1619)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.os.Parcel.writeBundle(Parcel.java:605)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.content.Intent.writeToParcel(Intent.java:6814)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.app.ActivityManagerProxy.startActivity

(ActivityManagerNative.java:1910)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1415)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.app.Activity.startActivityForResult(Activity.java:3446)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.app.Activity.startActivityForResult(Activity.java:3407)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.support.v4.app.FragmentActivity.startActivityForResult

(FragmentActivity.java:817)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.app.Activity.startActivity(Activity.java:3617)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.app.Activity.startActivity(Activity.java:3585)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at com.software.chat.Adapters.Websites_ListAdapter$1.onClick

(Websites_ListAdapter.java:211)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.view.View.performClick(View.java:4211)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.view.View$PerformClick.run(View.java:17267)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.os.Handler.handleCallback(Handler.java:615)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.os.Handler.dispatchMessage(Handler.java:92)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.os.Looper.loop(Looper.java:137)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.app.ActivityThread.main(ActivityThread.java:4898)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at java.lang.reflect.Method.invokeNative(Native Method)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at java.lang.reflect.Method.invoke(Method.java:511)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run

(ZygoteInit.java:1006)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at dalvik.system.NativeStart.main(Native Method)
04-25 15:38:07.474: E/AndroidRuntime(10250): Caused by: java.io.NotSerializableException: 

org.jivesoftware.smackx.muc.MultiUserChat
04-25 15:38:07.474: E/AndroidRuntime(10250):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1364)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at java.io.ObjectOutputStream.writeObjectInternal

(ObjectOutputStream.java:1671)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1517)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1481)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:979)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at java.io.ObjectOutputStream.defaultWriteObject

(ObjectOutputStream.java:368)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1074)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1404)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at java.io.ObjectOutputStream.writeObjectInternal

(ObjectOutputStream.java:1671)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1517)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1481)
04-25 15:38:07.474: E/AndroidRuntime(10250):    at android.os.Parcel.writeSerializable(Parcel.java:1274)
04-25 15:38:07.474: E/AndroidRuntime(10250):    ... 24 more

I know there are many ways to pass objects between activities but i want to know why is it happening this way and what does serializable do in the background ?

Any Help regarding this matter is greatly appreciated.

like image 937
Sheraz Ahmad Khilji Avatar asked Apr 25 '13 11:04

Sheraz Ahmad Khilji


1 Answers

If you'll look into Bundle sources you'll see that it uses Map for storing objects and will only serialize objects when Bundle itself is serialized.

It seems that Bundle is not serialized when passed to fragments. It can be optimization trick or implementation "bug".

But when you want to start new activity Bundle will be serialized and than deserialized. Thats why you have this exception only for Activities.

like image 144
MatrixDev Avatar answered Oct 15 '22 22:10

MatrixDev