0

So I thought I would try out Parcelling in Android today, quickly mocked this up:

public class Unit implements Parcelable {
    private String unitName;
    private int view;
    private Double value;

    /**
     * Constructor
     */
    public Unit() { }

    /**
     * Constructor
     * @param unitName
     */
    public Unit(String unitName) {
        this.unitName = unitName;
    }

    /**
     * Constructor
     * @param unitName
     * @param view
     */
    public Unit(String unitName, int view, Double value) {
        this.unitName = unitName;
        this.view = view;
        this.value = value;
    }

    /**
     * Set the name of the unit of measurement
     * @param name
     */
    public void setUnitName(String name) {
        this.unitName = name;
    }

    /**
     * Set whether the unit of measurement is viewable
     * @param view
     */
    public void setView(int view) {
        this.view = view;
    }

    /**
     * Set the value of the unit
     * @param value
     */
    public void setValue(Double value) { this.value = value; }

    /**
     * Return the unit name
     * @return unitName
     */
    public String getUnitName() {
        return unitName;
    }

    /**
     * Return whether the unit is viewable
     * @return view
     */
    public int getView() {
        return view;
    }

    /**
     * Return the value of this unit
     * @return value
     */
    public Double getValue() { return value; }

    /**
     * Methods for parcelling here
     */

    /**
     * Constructor for parcelling
     * @param in
     */
    public Unit(Parcel in) {
        //
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {
        dest.writeList(new ArrayList<Unit>() {
            //huh?
        });
    }

    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        public Unit createFromParcel(Parcel in) {
            return new Unit(in);
        }

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

As you will probably note my implementation of the methods that I override from the Parcelable interface are incomplete. But Carrying on, this class is just an object that is supposed to be parcelable to another class.

Now here is my main activity:

public class MyActivity extends Activity {
    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button send = (Button) findViewById(R.id.sendParcel);
        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ArrayList<Unit> units = getUnits();
                Intent i = new Intent(getApplicationContext(), UnitListActivity.class);
                i.putParcelableArrayListExtra("units", units);
                startActivity(i);
            }
        });
    }

    /**
     * Return an arraylist of units
     * @return units
     */
    public ArrayList<Unit> getUnits() {
        ArrayList<Unit> units = new ArrayList<Unit>();
        units.add(new Unit("acceleration", 1, 56.45));
        units.add(new Unit("kilograms", 0, 5830.54345));
        units.add(new Unit("metres", 1, 543.54));
        units.add(new Unit("kilometres", 1, 32.43));
        units.add(new Unit("grams", 1, 453.654));
        units.add(new Unit("kilograms", 0, 8.5));
        units.add(new Unit("litres", 1, 344.3));
        units.add(new Unit("millilitres", 0, 4543.879));
        units.add(new Unit("decimeter", 1, 5084903.564567));
        return units;
    }
}

Basically there is a button when pressed will create an Intent and try to parcel an ArrayList with the Object that implements the Parcelable interface. The class it is trying to pass it to is a ListActivity the code for which is here:

public class UnitListActivity extends ListActivity {

    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        UnitListAdapter mTypeAdapter = new UnitListAdapter(getApplicationContext(), bundle.getParcelableArrayList("units"));
        setListAdapter(mTypeAdapter);
    }
}

I made this adapter for the ListActivity here:

public class UnitListAdapter extends ArrayAdapter<Unit> {

    private ArrayList<Unit> unitsList;
    private Context context;

    public UnitListAdapter(Context c, ArrayList<Unit> units) {
        super(c, R.layout.unit_values, units);
        this.context = c;
        this.unitsList = units;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parentView) {
        View view = null;
        LayoutInflater inflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflator.inflate(R.layout.unit_values, null);
        TextView textView = (TextView) view.findViewById(R.id.unit_name);
        CheckBox checkBox = (CheckBox) view.findViewById(R.id.check);

        //check box set on check changed listener if I get this far for later

        if(unitsList.get(position).getView() == 1) {
            textView.setText(unitsList.get(position).getUnitName());
            checkBox.setChecked(true);
        } else {
            textView.setText(unitsList.get(position).getUnitName());
        }

        return view;
    }

}

Now what I don't understand is why in the ListActivity this line: UnitListAdapter mTypeAdapter = new UnitListAdapter(getApplicationContext(), bundle.getParcelableArrayList("units")); complains that instead of getting Unit objects, it is getting Parcelable objects, since class Unit implements them.

Does this mean that in my adapter I have to change the list to expect Parcelable objects and if, it means it is going to change how I read them??

I also don't understand writeToParcel, the documentation says that it will flatten the object, so I thought that since I want to flatten the the list I am going to need the writeList method, but what after that? it seems like it is flattening the Unit object not the list.

This also leads me to ask about the constructor:

public Unit(Parcel in) {
        //
}

I am guessing that I need to do something like this:

readTypedList() - I don't understand why I have to do this since I will be creating parcels. So I am not sure how to go about implementing this thing...I would really like insight into how parcelling is working, I didn't find the documentation that helpful and how in this example it would work successfully. Help and advice is very much appreciated.

user2405469
  • 1,953
  • 2
  • 22
  • 43

2 Answers2

0

I think you need to explicitly tell the Parcelable Creator what type it needs to create, so try changing your code to this:

public static final Parcelable.Creator<Unit> CREATOR = new Parcelable.Creator<Unit>() {
    public Unit createFromParcel(Parcel in) {
        return new Unit(in);
    }

    public Unit[] newArray(int size) {
        return new Unit[size];
    }
};
John J Smith
  • 11,435
  • 9
  • 53
  • 72
  • Sorry, but it doesn't work, UnitListAdapter mTypeAdapter = new UnitListAdapter(getApplicationContext(), bundle.getParcelableArrayList("units")); keeps asking me to cast bundle.getParcelableArrayList to ArrayList but my Unit class implements it, so I don't know why it is complaining, can't extend an interface so... – user2405469 Aug 04 '14 at 08:00
0
public static final Parcelable.Creator<Unit> CREATOR = new Parcelable.Creator<Unit>() {
    public Unit createFromParcel(Parcel in) {
        Unit u = new Unit();
        u.setUnitName(in.readString());
        //...
        //populate all atributes
        return u;
    }

    public Unit[] newArray(int size) {
        return new Unit[size];
    }
};
Bono
  • 4,757
  • 6
  • 48
  • 77
  • Could you please provide more information on your answer? It's usually good practice to explain a little about the answers you post. – Bono Mar 07 '15 at 14:20