AndroidDev
AndroidDev

Reputation: 21237

Intent putExtra ArrayList<NameValuePair>

Does anyone know how to add an ArrayList<NameValuePair> to an Intent as an extra?

ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("first_name", first_name));
nameValuePairs.add(new BasicNameValuePair("last_name", last_name));
nameValuePairs.add(new BasicNameValuePair("email", email));
nameValuePairs.add(new BasicNameValuePair("password", password));

/* Move on to step 2 */
Intent intent = new Intent(RegisterActivity1.this, RegisterActivity2.class);
intent.putExtra("nvp", nameValuePairs);
startActivity(intent);

Here is the class declaration for RegisterActivity2:

public class RegisterActivity2 extends Activity implements Serializable {
}

The error in the logcat is:

> Parcel: unable to marshal value first_name="whatever"

After implementing the suggestion by Ted Hopp, I still get an error. Here is the stack trace:

08-04 22:10:16.095: E/AndroidRuntime(5065): FATAL EXCEPTION: main
> 08-04 22:10:16.095: E/AndroidRuntime(5065):
> java.lang.RuntimeException: Unable to start activity
> ComponentInfo{/.RegisterActivity2}: java.lang.RuntimeException:
> Parcelable encountered IOException reading a Serializable object (name
> = database.NVP) 08-04 22:10:16.095: E/AndroidRuntime(5065):   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2070)
> 08-04 22:10:16.095: E/AndroidRuntime(5065):   at
> android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2095)
> 08-04 22:10:16.095: E/AndroidRuntime(5065):   at
> android.app.ActivityThread.access$600(ActivityThread.java:135) 08-04
> 22:10:16.095: E/AndroidRuntime(5065):     at
> android.app.ActivityThread$H.handleMessage(ActivityThread.java:1201)
> 08-04 22:10:16.095: E/AndroidRuntime(5065):   at
> android.os.Handler.dispatchMessage(Handler.java:99) 08-04
> 22:10:16.095: E/AndroidRuntime(5065):     at
> android.os.Looper.loop(Looper.java:137) 08-04 22:10:16.095:
> E/AndroidRuntime(5065):   at
> android.app.ActivityThread.main(ActivityThread.java:4849) 08-04
> 22:10:16.095: E/AndroidRuntime(5065):     at
> java.lang.reflect.Method.invokeNative(Native Method) 08-04
> 22:10:16.095: E/AndroidRuntime(5065):     at
> java.lang.reflect.Method.invoke(Method.java:511) 08-04 22:10:16.095:
> E/AndroidRuntime(5065):   at
> com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
> 08-04 22:10:16.095: E/AndroidRuntime(5065):   at
> com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562) 08-04
> 22:10:16.095: E/AndroidRuntime(5065):     at
> dalvik.system.NativeStart.main(Native Method) 08-04 22:10:16.095:
> E/AndroidRuntime(5065): Caused by: java.lang.RuntimeException:
> Parcelable encountered IOException reading a Serializable object (name
> = database.NVP) 08-04 22:10:16.095: E/AndroidRuntime(5065):   at android.os.Parcel.readSerializable(Parcel.java:2144) 08-04
> 22:10:16.095: E/AndroidRuntime(5065):     at
> android.os.Parcel.readValue(Parcel.java:2016) 08-04 22:10:16.095:
> E/AndroidRuntime(5065):   at
> android.os.Parcel.readListInternal(Parcel.java:2235) 08-04
> 22:10:16.095: E/AndroidRuntime(5065):     at
> android.os.Parcel.readArrayList(Parcel.java:1655) 08-04 22:10:16.095:
> E/AndroidRuntime(5065):   at
> android.os.Parcel.readValue(Parcel.java:1986) 08-04 22:10:16.095:
> E/AndroidRuntime(5065):   at
> android.os.Parcel.readMapInternal(Parcel.java:2226) 08-04
> 22:10:16.095: E/AndroidRuntime(5065):     at
> android.os.Bundle.unparcel(Bundle.java:223) 08-04 22:10:16.095:
> E/AndroidRuntime(5065):   at
> android.os.Bundle.getSerializable(Bundle.java:1254) 08-04
> 22:10:16.095: E/AndroidRuntime(5065):     at
> android.content.Intent.getSerializableExtra(Intent.java:4268) 08-04
> 22:10:16.095: E/AndroidRuntime(5065):     at
> .RegisterActivity2.onCreate(RegisterActivity2.java:24) 08-04
> 22:10:16.095: E/AndroidRuntime(5065):     at
> android.app.Activity.performCreate(Activity.java:5244) 08-04
> 22:10:16.095: E/AndroidRuntime(5065):     at
> android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1082)
> 08-04 22:10:16.095: E/AndroidRuntime(5065):   at
> android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2034)
> 08-04 22:10:16.095: E/AndroidRuntime(5065):   ... 11 more 08-04
> 22:10:16.095: E/AndroidRuntime(5065): Caused by:
> java.io.InvalidClassException:
> org.apache.http.message.BasicNameValuePair; IllegalAccessException
> 08-04 22:10:16.095: E/AndroidRuntime(5065):   at
> java.io.ObjectStreamClass.resolveConstructorClass(ObjectStreamClass.java:694)
> 08-04 22:10:16.095: E/AndroidRuntime(5065):   at
> java.io.ObjectStreamClass.newInstance(ObjectStreamClass.java:655)
> 08-04 22:10:16.095: E/AndroidRuntime(5065):   at
> java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:1816)
> 08-04 22:10:16.095: E/AndroidRuntime(5065):   at
> java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:787)
> 08-04 22:10:16.095: E/AndroidRuntime(5065):   at
> java.io.ObjectInputStream.readObject(ObjectInputStream.java:2003)
> 08-04 22:10:16.095: E/AndroidRuntime(5065):   at
> java.io.ObjectInputStream.readObject(ObjectInputStream.java:1960)
> 08-04 22:10:16.095: E/AndroidRuntime(5065):   at
> android.os.Parcel.readSerializable(Parcel.java:2142) 08-04
> 22:10:16.095: E/AndroidRuntime(5065):     ... 23 more

Upvotes: 28

Views: 59600

Answers (5)

Ted Hopp
Ted Hopp

Reputation: 234807

As others have noted, when you want to pass an array as an intent extra, the elements need to implement Serializable. In your case, the approach is fairly simple (not quite — see below): define your own subclass of BasicNameValuePair and declare it to implement the interface.

public class NVP extends BasicNameValuePair implements Serializable {
    public NVP(String name, String value) {
        super(name, value);
    }
}

Then you can use it like you've been trying:

ArrayList<NVP> nameValuePairs = new ArrayList<NVP>();
nameValuePairs.add(new NVP("first_name", first_name));
nameValuePairs.add(new NVP("last_name", last_name));
nameValuePairs.add(new NVP("email", email));
nameValuePairs.add(new NVP("password", password));

/* Move on to step 2 */
Intent intent = new Intent(RegisterActivity1.this, RegisterActivity2.class);
intent.putExtra("nvp", nameValuePairs);
startActivity(intent);

On the receiving end, you'll need to pull it out with:

ArrayList<NVP> nameValuePairs = (ArrayList<NVP>) intent.getSerializable("nvp");

EDIT Well, the above won't work because BasicNameValuePair doesn't have a default constructor and the serialization mechanism requires non-serializable ancestor classes to have a default constructor. Otherwise you'll get an exception on deserialization.

Unfortunately, this means that the solution isn't as simple as I made out. One work-around is to define your own class to implement Parcelable, as @keerthana murugesan suggests in his answer. If you've implemented Parcelable before, you know it's a bit of a pain. Another work-around is to define a class that wraps a BasicNameValuePair (instead of deriving from it) and manages its own serialization:

public class NVP implements NameValuePair, Serializable {
    private BasicNameValuePair nvp;

    public NVP(String name, String value) {
        nvp = new BasicNameValuePair(name, value);
    }

    @Override
    public String getName() {
        return nvp.getName();
    }

    @Override
    public String getValue() {
        return nvp.getValue();
    }

    // serialization support

    private static final long serialVersionUID = 1L;

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.writeString(nvp.getName());
        out.writeString(nvp.getValue());
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        nvp = new BasicNameValuePair(in.readString(), in.readString());
    }

    private void readObjectNoData() throws ObjectStreamException {
        // nothing to do
    }
}

Upvotes: 24

Ogmi
Ogmi

Reputation: 257

I had the same problem, trying to send objects in ArrayList without implementing Seiralizable in Object class.

The shortcut solution was to envelop ArrayList in Bundle.

So, in the first activity ->

ArrayList<Object> objects = new ArrayList<Object>(); 
// Object class does not implement Serializable interface

Bundle extra = new Bundle();
extra.putSerializable("objects", objects);

Intent intent = new Intent(getBaseContext(), ShowSpread.class);
intent.putExtra("extra", extra);

Second activity ->

Bundle extra = getIntent().getBundleExtra("extra");
ArrayList<Object> objects = (ArrayList<Object>) extra.getSerializable("objects")

Works fine.

Upvotes: 23

keerthana murugesan
keerthana murugesan

Reputation: 581

This can be achieved using Parcelable interface.

  1. Make your BasicNameValuePair class to implement Parcelable interface.see this for more reference.

    public class BasicNameValuePair implements Parcelable{
    
    }
    
  2. Add these objects to an ArrayList as you did above,

    ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
    nameValuePairs.add(new BasicNameValuePair("first_name", first_name));
    nameValuePairs.add(new BasicNameValuePair("last_name", last_name));
    nameValuePairs.add(new BasicNameValuePair("email", email));
    nameValuePairs.add(new BasicNameValuePair("password", password));
    
  3. Pass these into intent using putParcelableArrayListExtra().

    intent.putParcelableArrayListExtra ("nvp", nameValuePairs);
    startActivity(intent);
    

Upvotes: 0

taxeeta
taxeeta

Reputation: 1198

You need to pass a Object array as a Serializable into the intent. The Object array must consist of objects that are inturn Serializable.

ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("first_name", first_name));
nameValuePairs.add(new BasicNameValuePair("last_name", last_name));
nameValuePairs.add(new BasicNameValuePair("email", email));
nameValuePairs.add(new BasicNameValuePair("password", password));

Here BaseNameValuePair needs to be a class that implements Serializable. Use toArray of ArrayList into put, and typecast it to Serializable. In your getter Activity use getSerializable method on the intent.

Upvotes: 1

Karakuri
Karakuri

Reputation: 38595

For this to work, the genericized type your List holds must implement Serializable.

Upvotes: 0

Related Questions