Search code examples
androidobjecthashhashmapparcel

How would I correctly implement parcel/parcelable in a Hash of objects in Java/Android


I have the following classes: Experiment and Measurements. I pass a HashMap containing Experiment objects as a value, and their Experiment.getExperimentName as a key, between Android activities.

These Experiment objects in turn contain a HashMap of Measurements objects. This HashMap has a the Measurements objects as a value, and their Measurements.getMeasurements as a key.

These Measurements objects then contain an ArrayList of doubles.

I've tried many variations of using bundle or directly putting in a parcel, but I keep getting a "ClassNotFoundException when unmarshalling: nl.bioinf.thema12.labpal.objects.Measurements" when I read the HashMap in the new activity.

How Would I correctly implement parcel/parcelable?

The Experiment Class:

package nl.bioinf.thema12.labpal.objects;
import java.util.HashMap;
//import java.util.Set;

import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;

/**
 * @author roy
 * a class which describes an experiment
 */
public class Experiment implements Parcelable{
    private String experimentName = "";
    private HashMap<String,Measurements> measurements = new HashMap<String,Measurements>();

    //every Experiment needs a name to make it unique
    public Experiment(String experimentName) {
        this.experimentName=experimentName;
    }

    /**
     * a method which adds values to a measurement
     * @param   measurementName the name of the measurement you want to write a value to
     * @param   measurement the value of the measurement you want to add
     * @return  the sequence from the fasta
     */
    public void addValueToMeasurements(String measurementName, double measurement){
        //try to add the measurement
        if(measurements.get(measurementName)== null){
            Measurements m = new Measurements(measurementName);
            m.addMeasurement(measurement);
            measurements.put(measurementName,m);
        }
        //if the measurement does not exist, create it
        else{
            measurements.get(measurementName).addMeasurement(measurement);  
        }
    }
    /**
     * a method which returns the experiment name
     * @return  the experiment name
     */ 
    public String getExperimentName(){
        return experimentName;
    }



    //This makes the object parselable, I don't understand why
    /**
     * a constructor for the parcelable variant of the object
     */     
    public Experiment(Parcel in){
        measurements = new HashMap<String,Measurements>();
        readFromParcel(in);
    }

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    /**
     * a method which writes the objects to a parcel
     */ 
    public void writeToParcel(Parcel dest, int flags) {
        //dest.writeString(experimentName);
        //for(String s: (Set<String>)measurements.keySet()){
            //dest.writeString(s);
            //dest.writeValue(measurements.get(s));
        //}
        Bundle b = new Bundle();
        b.putString("experimentName", experimentName);
        b.putSerializable("measurements", measurements);
        dest.writeBundle(b);
    }

    /**
     * a method which reads from a parcel
     */ 
    public void readFromParcel(Parcel in){
        //experimentName = in.readString();
        Bundle b = in.readBundle();
        experimentName = b.getString("experimentName");
        measurements = (HashMap<String, Measurements>)b.getSerializable("measurements");
    }

    /**
     * generic parcelable creator method
     */ 
    public static final Parcelable.Creator CREATOR =
        new Parcelable.Creator() {
            public Experiment createFromParcel(Parcel in) {
                return new Experiment(in);
            }

            public Experiment[] newArray(int size) {
                return new Experiment[size];
            }
     };


}

The Measurements Class

package nl.bioinf.thema12.labpal.objects;

import java.util.ArrayList;

import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
/**
 * @author roy
 * a class which describes a group of measurements
 */

public class Measurements implements Parcelable{
    private ArrayList<Double> measurements;
    private String measurementName;

    //each measurement has at least a name and an empty list of measurements
    public Measurements(String measurementName) {
        this.measurementName=measurementName;
        measurements = new ArrayList<Double>();
    }

    /**
     * a method which adds a measurement to an ArrayList of measurements
     * @param   measurement a measurement to add to the ArrayList
     */
    public void addMeasurement(double measurement){
        measurements.add(measurement);
        System.out.println("added a measurement");
    }

    /**
     * a method which returns the measurement name
     * @return  the measurement name
     */
    public String getMeasurementName(){
        return measurementName;
    }

    /**
     * a method which returns an ArrayList of the values in the measurement
     * @return  the values of the measurements in an ArrayList
     */
    public ArrayList<Double> getMeasurements(){
        return measurements;
    }

    //This makes the object parselable, I don't understand why
    /**
     * a constructor for the parcelable variant of the object
     */     
    public Measurements(Parcel in){
        measurements = new ArrayList<Double>();
        readFromParcel(in);

    }

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    /**
     * a method which writes the objects to a parcel
     */ 
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        //dest.writeString(measurementName);
        //dest.writeList(measurements);
        Bundle b = new Bundle();
        b.putString("measurementName", measurementName);
        b.putSerializable("measurements", measurements);
    }

    /**
     * a method which reads from a parcel
     */ 
    public void readFromParcel(Parcel in){
        //measurementName = in.readString();
        //measurements = in.readArrayList(Object.class.getClassLoader());
        Bundle b = in.readBundle();
        measurementName = b.getString("measurementName");
        measurements = (ArrayList<Double>)b.getSerializable("measurements");
    }

    /**
     * generic parcelable creator method
     */ 
    public static final Parcelable.Creator CREATOR =
        new Parcelable.Creator() {
            public Measurements createFromParcel(Parcel in) {
                return new Measurements(in);
            }

            public Measurements[] newArray(int size) {
                return new Measurements[size];
            }
     };
}

code for the activity that receives the bundle

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //get the intent passed by the other activity
    Bundle b = getIntent().getExtras();
    experiment = b.getParcelable("nl.bioinf.thema12.labpal.objects.Experiment");
    setContentView(R.layout.activity_show_table);
}

code for the activity that sends the bundle

//setup the table button
        table = (Button)findViewById(R.id.button_activityMain_table);
        table.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v){
                try{
                    Intent intentToPassToShowTable = new Intent(MainActivity.this, ShowTable.class);
                    Bundle b = new Bundle();
                    b.putParcelable("nl.bioinf.thema12.labpal.objects.Experiment", experiments.get(experimentName.getSelectedItem().toString()));
                    intentToPassToShowTable.putExtras(b);
                    startActivity(intentToPassToShowTable);
                }
                catch(Exception e){
                    e.printStackTrace();
                }
            }
        });

Solution

  • Hi There Try this code it's working fine

      package com.example.objectsharing;
    
    import java.util.ArrayList;
     import java.util.HashMap;
    
    import android.os.Bundle;
    import android.os.Parcel;
    import android.os.Parcelable;
    
    public class Experiment implements Parcelable {
    private String experimentName = "";
    private HashMap<String, ArrayList<Double>> measurements = new HashMap<String, ArrayList<Double>>();
    
    // every Experiment needs a name to make it unique
    public Experiment(String experimentName) {
        this.experimentName = experimentName;
    }
    
    /**
     * a method which adds values to a measurement
     * 
     * @param measurementName
     *            the name of the measurement you want to write a value to
     * @param measurement
     *            the value of the measurement you want to add
     * @return the sequence from the fasta
     */
    public void addValueToMeasurements(String measurementName,
            double measurement) {
        // try to add the measurement
        if (measurements.get(measurementName) == null) {
            // Measurements m = new Measurements(measurementName);
            ArrayList<Double> _data = new ArrayList<Double>();
            // m.addMeasurement(measurement);
            _data.add(measurement);
            measurements.put(measurementName, _data);
        }
        // if the measurement does not exist, create it
        else {
            measurements.get(measurementName).add(measurement);
        }
    }
    
    /**
     * a method which returns the experiment name
     * 
     * @return the experiment name
     */
    public String getExperimentName() {
        return experimentName;
    }
    
    // This makes the object parselable, I don't understand why
    /**
     * a constructor for the parcelable variant of the object
     */
    public Experiment(Parcel in) {
        measurements = new HashMap<String, ArrayList<Double>>();
        readFromParcel(in);
    }
    
    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }
    
    @Override
    /**
     * a method which writes the objects to a parcel
     */
    public void writeToParcel(Parcel dest, int flags) {
        // dest.writeString(experimentName);
        // for(String s: (Set<String>)measurements.keySet()){
        // dest.writeString(s);
        // dest.writeValue(measurements.get(s));
        // }
        Bundle b = new Bundle();
        b.putString("experimentName", experimentName);
        b.putSerializable("measurements", measurements);
        dest.writeBundle(b);
    }
    
    /**
     * a method which reads from a parcel
     */
    public void readFromParcel(Parcel in) {
        // experimentName = in.readString();
        Bundle b = in.readBundle();
        experimentName = b.getString("experimentName");
        measurements = (HashMap<String, ArrayList<Double>>) b
                .getSerializable("measurements");
    }
    
    /**
     * generic parcelable creator method
     */
    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        public Experiment createFromParcel(Parcel in) {
            return new Experiment(in);
        }
    
        public Experiment[] newArray(int size) {
            return new Experiment[size];
        }
    };
    

    }