2

Ive come in to a problem that has me completely stumped beyond belief. My custom object seems to be losing the values after it is sent via intent to a new activity. Why would an object lose values of its instance variables only after being passed with intent?

I have custom object that implements Parcelable, for storing specific data.

public class Vehicle implements Parcelable, Serializable{
private static final String TAG = "vehicleObject";
public String vehicleType;
public String refID;
public String title;

public HashMap<String, String> reservedSpecs;
public HashMap<String, String> generalSpecs;
public HashMap<String, String> engineSpecs;
public HashMap<String, String> powerTrainSpecs;
public HashMap<String, String> otherSpecs;

public Vehicle(String vehicleType, String year, String make, String model){
    this.refID = UUID.randomUUID().toString();
    this.title = year + " " + make + " " + model;
    this.vehicleType = vehicleType;
    this.reservedSpecs = new HashMap<>();
    this.reservedSpecs.put("year", year);
    this.reservedSpecs.put("make", make);
    this.reservedSpecs.put("model", model);
}

public Vehicle(Parcel source){
    Bundle bundle = source.readBundle(getClass().getClassLoader());
    vehicleType = bundle.getString("vehicleType");
    refID = bundle.getString("refID");
    title = bundle.getString("title");

    reservedSpecs = (HashMap) bundle.getSerializable("reserved");
    generalSpecs = (HashMap) bundle.getSerializable("general");
    engineSpecs = (HashMap) bundle.getSerializable("engine");
    powerTrainSpecs = (HashMap) bundle.getSerializable("power");
    otherSpecs = (HashMap) bundle.getSerializable("other");
}

@Override
public void writeToParcel(Parcel dest, int flags){
    Bundle bundle = new Bundle();
    bundle.putString("vehicleType", vehicleType);
    bundle.putString("refID", refID);
    bundle.putString("title", title);
    bundle.putSerializable("reserved", reservedSpecs);
    bundle.putSerializable("general", generalSpecs);
    bundle.putSerializable("engine", engineSpecs);
    bundle.putSerializable("power", powerTrainSpecs);
    bundle.putSerializable("other", otherSpecs);

    dest.writeBundle(bundle);
}

@Override
public int describeContents(){
    return 0;
}

/**
  *Generic getters/Setters for all instance variables 
**/

/**
 * Creator required for class implementing the parcelable interface.
 */
public static final Parcelable.Creator<Vehicle> CREATOR = new Creator<Vehicle>() {

    @Override
    public Vehicle createFromParcel(Parcel source) {
        return new Vehicle(source);
    }

    @Override
    public Vehicle[] newArray(int size) {
        return new Vehicle[size];
    }
};

}

I then, in my main activity, pass the object(Vehicle) using a listener. The object lives in ArrayList

public class fragment_overview extends Fragment implements UpdateUI{
    private static final String TAG = "frg_ovrvw";

    private final String SHARED_PREF = "com.kd8bny.maintenanceman_preferences";

    private Toolbar toolbar;
    private Context context;
    private SharedPreferences sharedPreferences;
    private RecyclerView cardList;
    private RecyclerView.LayoutManager cardMan;
    private RecyclerView.Adapter cardListAdapter;

    private ArrayList<Vehicle> roster;
    private String mUnit;

    public fragment_overview() {

    }

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        context = getActivity().getApplicationContext();
        roster = new ArrayList<>(new SaveLoadHelper(context).load());
    }

    @Override
    public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View view = inflater.inflate(R.layout.fragment_overview, container, false);

        sharedPreferences = context.getSharedPreferences(SHARED_PREF, 0);

        //Toolbar
        toolbar = (Toolbar) view.findViewById(R.id.tool_bar);
        ((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
        ((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        ((AppCompatActivity)getActivity()).getSupportActionBar().setHomeButtonEnabled(true);

        //cards
        mUnit = sharedPreferences.getString("prefUnitDist", "");

        cardList = (RecyclerView) view.findViewById(R.id.overview_cardList);
        cardMan = new LinearLayoutManager(getActivity());
        cardList.setLayoutManager(cardMan);
        cardList.addOnItemTouchListener(new RecyclerViewOnItemClickListener(context, cardList, new RecyclerViewOnItemClickListener.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int pos) {
                if (!roster.isEmpty()) { //THIS INTENT HERE
                    Intent viewIntent = new Intent(getActivity(), test.class);
                    Bundle bundle = new Bundle();
                    bundle.putParcelable("vehicle", roster.get(pos));
                    bundle.putInt("pos", pos);
                    viewIntent.putExtra("bundle", bundle);
                    view.getContext().startActivity(viewIntent);
                } else {
                    Intent addIntent = new Intent(getActivity(), activity_add_fleetRoster.class);
                    addIntent.putParcelableArrayListExtra("roster", roster);
                    view.getContext().startActivity(addIntent);
                }
            }

            @Override
            public void onItemLongClick(View view, int pos) {}}));

      return view;

Once the intent is sent I receive it in my new activity.

public class test extends AppCompatActivity {
private ArrayList<Vehicle> roster;
private Vehicle vehicle;
RecyclerView cardList;
RecyclerView.LayoutManager cardMan;
RecyclerView.Adapter cardListAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);


    Bundle bundle = getIntent().getBundleExtra("bundle");
    vehicle = bundle.getParcelable("vehicle");
    int vehiclePos = bundle.getInt("pos", -1);

    //Set recycler view
    cardList = (RecyclerView) findViewById(R.id.info_cardList);
    cardMan = new LinearLayoutManager(this);
    cardList.setLayoutManager(cardMan);

    }

@Override
public void onResume(){
    super.onResume();

    cardListAdapter = new adapter_info(vehicle);
    cardList.setAdapter(cardListAdapter);
 }

}

The adapter then takes the vehicle object and uses getters to generate cards

public adapter_info(Vehicle vehicle) {
    ArrayList<HashMap> temp = new ArrayList<>();
    temp.add(vehicle.getGeneralSpecs());
    temp.add(vehicle.getEngineSpecs());
    temp.add(vehicle.getPowerTrainSpecs());
    temp.add(vehicle.getOtherSpecs());       
}
/**
*Adapter stuff such as onCreateViewHodler and bind
**/

Now this all works fine and dandy the first run-through. When I Try to do anything after including sending this object through another intent, resuming the activity, anything using getters and setters on my object. The Hashmaps in my object lose their values Below is a gif of what happens when you press recents and return to the app. The app never loses focus. Pressing Recents

Here is a log showing what happens

 01-09 20:27:19.850 2359-2359/com.kd8bny.maintenanceman D/TEST!!!: create{G=G}{E=E}{P=P}{Po=Oo}   //All 4 hashmaps with values
01-09 20:27:19.850 2359-2359/com.kd8bny.maintenanceman A/getGeneralSpecs: get{G=G} //A log of each hashmap in the object's getter method
01-09 20:27:19.850 2359-2359/com.kd8bny.maintenanceman A/getEngineSpecs: get{E=E}
01-09 20:27:19.851 2359-2359/com.kd8bny.maintenanceman A/getPowerTrainSpecs: get{P=P}
01-09 20:27:19.851 2359-2359/com.kd8bny.maintenanceman A/getOtherSpecs: get{Po=Oo}
01-09 20:27:19.851 2359-2359/com.kd8bny.maintenanceman E/adptr_inf: [{G=G}, {E=E}, {P=P}, {Po=Oo}] //Finally what the adapter sees using the getter method
01-09 20:27:19.851 2359-2359/com.kd8bny.maintenanceman E/adptr_inf: [{G=G}, {E=E}, {P=P}, {Po=Oo}]

After this ran here is the object called again

    01-09 20:28:13.382 2359-2359/com.kd8bny.maintenanceman A/getGeneralSpecs: get{} //Empty hashmap that had G=G
01-09 20:28:13.382 2359-2359/com.kd8bny.maintenanceman A/getEngineSpecs: get{}  //Empty hashmap that had E=E
01-09 20:28:13.383 2359-2359/com.kd8bny.maintenanceman A/getPowerTrainSpecs: get{}  //Empty hashmap that had P=P
01-09 20:28:13.383 2359-2359/com.kd8bny.maintenanceman A/getOtherSpecs: get{Po=Oo}   //hashmap that retains its value
01-09 20:28:13.383 2359-2359/com.kd8bny.maintenanceman E/adptr_inf: [{Po=Oo}] //And what the adapter sees as it calls on the object again
01-09 20:28:13.383 2359-2359/com.kd8bny.maintenanceman E/adptr_inf: [{Po=Oo}]

Why are these value disappearing? Can I do this differently to fix the problem. I have tried using a singeton and passing serializable with the same results. Thanks in advance!

kd8bny
  • 156
  • 1
  • 10
  • I don't see the problem but you could try switching to Parceler and see if that fixes it. https://github.com/johncarl81/parceler – nasch Jan 11 '16 at 01:10
  • Interesting project. Ill give that a shot – kd8bny Jan 11 '16 at 20:49
  • So I narrowed down the problem a little. Turn out recycler view was acting weird because I placed the setAdapter in the onStart method. However the problem still exists when sending my object to another activity. Turns out parcelable works fine but my instance of my object changes after the onResume method runs. ie losing the data. – kd8bny Jan 24 '16 at 19:34

1 Answers1

0

I finally figured out what the issue was in this problem.

JAVA is pass by value

My custom object would pass value of the hashmap whenever I created a new object. I would then edit the object or call on it and the hashmap would return its last key/value pair. I solved the issue by using Gson to serialize the hashmap and return it to its form later.

kd8bny
  • 156
  • 1
  • 10