Deepanshu
Deepanshu

Reputation: 498

How do I pass custom ArrayAdapter Object between Intents with serialization

Background:
I am just starting with Android and I have learned about Intents and ListView. I have am creating a simple app where a user enter some information and that information is added into ListView. For this I have created a ListView in my MainActivity class. Created a class for Objects named User and created Custom ArrayAdapter UserAdapter. Both of my classed User and UserAdapter implements Serializable marker interface. Now whenever someone click on button from MainActivity class to add data a new Intent opens and takes input from that intent and return back to MainActivity intent. I am passing UserAdapter Object between intents.

Problem:
Now the problem Adapter Object is showing is not working in next Intent.

Code:
MainActivity.java

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //blah blah blah ...
        // Main code starts here

        ListView listView = (ListView) findViewById(R.id.list);
        ArrayList<User> arrayList = new ArrayList<>();
        UserAdapter adapter = new UserAdapter(this, arrayList);
        listView.setAdapter(adapter);

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(v.getContext(), AddUser.class);
                intent.putExtra("adapter", adapter);
                startActivity(intent);
            }
        });
    }
    //blah blah blah ...
}

UserAdapter.java

public class UserAdapter extends ArrayAdapter<User> implements Serializable {
    public UserAdapter(Context context, Collection<User> arrayList) {
       //call ArrayAdapter's constructor
       //context, layout, collection
        super(context, 0, (ArrayList<User>)arrayList);
    }

    @Override
    public View getView(int position, View obj, ViewGroup parent) {
        User user = getItem(position);
        if(obj == null) {
            obj = LayoutInflater.from(getContext()).inflate(R.layout.user_layout, parent, false);
        }
        TextView name = (TextView) obj.findViewById(R.id.user_name);
        TextView adress = (TextView) obj.findViewById(R.id.user_address);
        name.setText(user.getUserName());
        adress.setText(user.getUserAddress());
        return obj;
    }
}

User class also implements Serializable and I don't think you need that class implementation but if you want I can add that here.

Now My Second Activiy class AddUser.java

public class AddUser extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_user);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String name = ((EditText) findViewById(R.id.name)).getText().toString();
                String address = ((EditText) findViewById(R.id.address)).getText().toString();
                String contact = ((EditText) findViewById(R.id.contact)).getText().toString();
                String college = ((EditText) findViewById(R.id.college)).getText().toString();
                User user = new User(name, address);
                user.setCollege(college);
                user.setContact(contact);
                Intent intent = new Intent(v.getContext(), MainActivity.class);
                UserAdapter adapter = (UserAdapter)getIntent().getSerializableExtra("Adapter");
                adapter.add(user);
                finish();
                startActivity(intent);
            }
        });
    }
}

Logcat

02-20 18:35:37.264 12074-12074/com.example.deepanshu.customadapter3 E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                  Process: com.example.deepanshu.customadapter3, PID: 12074
                                                                                  java.lang.RuntimeException: Parcelable encountered IOException reading a Serializable object (name =com.example.deepanshu.customadapter3.UserAdapter)
        at android.os.Parcel.readSerializable(Parcel.java:2380)
        at android.os.Parcel.readValue(Parcel.java:2203)
        at android.os.Parcel.readArrayMapInternal(Parcel.java:2485)
        at android.os.BaseBundle.unparcel(BaseBundle.java:221)
        at android.os.BaseBundle.getSerializable(BaseBundle.java:988)
        at android.os.Bundle.getSerializable(Bundle.java:845)
        at android.content.Intent.getSerializableExtra(Intent.java:5256)
        at com.example.deepanshu.customadapter3.AddUser$2.onClick(AddUser.java:47)
        at android.view.View.performClick(View.java:4789)
        at android.view.View$PerformClick.run(View.java:19881)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5292)
        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.InvalidClassException: android.widget.ArrayAdapter; IllegalAccessException
        at java.io.ObjectStreamClass.resolveConstructorClass(ObjectStreamClass.java:712)
        at java.io.ObjectStreamClass.newInstance(ObjectStreamClass.java:673)
        at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:1796)
        at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:761)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1983)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1940)
        at android.os.Parcel.readSerializable(Parcel.java:2378)
        at android.os.Parcel.readValue(Parcel.java:2203) 
        at android.os.Parcel.readArrayMapInternal(Parcel.java:2485) 
        at android.os.BaseBundle.unparcel(BaseBundle.java:221) 
        at android.os.BaseBundle.getSerializable(BaseBundle.java:988) 
        at android.os.Bundle.getSerializable(Bundle.java:845) 
        at android.content.Intent.getSerializableExtra(Intent.java:5256) 
        at com.example.deepanshu.customadapter3.AddUser$2.onClick(AddUser.java:47) 
        at android.view.View.performClick(View.java:4789) 
        at android.view.View$PerformClick.run(View.java:19881) 
        at android.os.Handler.handleCallback(Handler.java:739) 
        at android.os.Handler.dispatchMessage(Handler.java:95) 
        at android.os.Looper.loop(Looper.java:135) 
        at android.app.ActivityThread.main(ActivityThread.java:5292) 
        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) 

You cannot checkout code here

Also check issue in my Github profile too.

Upvotes: 2

Views: 2219

Answers (1)

Khantil Choksi
Khantil Choksi

Reputation: 61

You can't pass your custom ArrayAdapter or any other BaseAdapter/ArrayAdapter object in intent.

As you know that to pass any object in intent it should be either Parcelable or Serializable.

As per documentation of Serializable interface https://developer.android.com/reference/java/io/Serializable.html

The serialization mechanism encodes an object's class name, the names of its non-transient fields (including non-public fields), and the values of all of those fields.

Here, when you implement Serializable interface to your custom ArrayAdapter class, it does not actually gets the ability of Serialization, because when you implement Serializable interface, all fields takes part in the Serialization process.

But android.widget.ArrayAdapter class itself does not implement Serializable interface. So indirectly your custom ArrayAdapter which inherited from android.widget.ArrayAdapter, is also not Serializable.

And considering your example, as mentioned in the comments, please call the intent with startActivityForResult() to get the object to be added to your custom adapter.

Hope so you can understand this!

Read more about Serialization process!

Upvotes: 2

Related Questions