Parcelable 自定义对象在通过意图传递时丢失实例值
Parcelable custom object losing instance values when passed with intent
我遇到了一个让我完全难以相信的问题。我的自定义对象在通过 intent 发送到新的 activity 后似乎丢失了值。为什么一个对象只有在通过意图传递后才会丢失其实例变量的值?
我有实现 Parcelable 的自定义对象,用于存储特定数据。
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];
}
};
}
然后,在我的主要 activity 中,我使用侦听器传递对象(车辆)。该对象位于 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;
发送意向后,我会在新 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);
}
}
然后适配器获取车辆对象并使用 getter 生成卡片
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
**/
现在这一切都很好,第一个 运行-through。当我在包括通过另一个意图发送此对象、恢复 activity 之后尝试执行任何操作时,任何在我的对象上使用 getter 和 setter 的操作。 我的对象中的 Hashmap 丢失了它们的值
下面是当您按最近和 return 到应用程序时会发生什么的动图。该应用程序永远不会失去焦点。
这是一个显示发生了什么的日志
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}]
在此之后运行这里是再次调用的对象
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}]
为什么这些值会消失?我可以用不同的方式来解决这个问题吗?我试过使用单例并传递可序列化的结果相同。
提前致谢!
我终于明白这个问题是什么问题了
JAVA是传值
每当我创建新对象时,我的自定义对象都会传递散列图的值。然后我会编辑对象或调用它,哈希图将 return 它的最后一个 key/value 对。我通过使用 Gson 序列化 hashmap 并稍后 return 将其转换为它的形式解决了这个问题。
我遇到了一个让我完全难以相信的问题。我的自定义对象在通过 intent 发送到新的 activity 后似乎丢失了值。为什么一个对象只有在通过意图传递后才会丢失其实例变量的值?
我有实现 Parcelable 的自定义对象,用于存储特定数据。
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];
}
};
}
然后,在我的主要 activity 中,我使用侦听器传递对象(车辆)。该对象位于 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;
发送意向后,我会在新 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);
}
}
然后适配器获取车辆对象并使用 getter 生成卡片
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
**/
现在这一切都很好,第一个 运行-through。当我在包括通过另一个意图发送此对象、恢复 activity 之后尝试执行任何操作时,任何在我的对象上使用 getter 和 setter 的操作。 我的对象中的 Hashmap 丢失了它们的值
下面是当您按最近和 return 到应用程序时会发生什么的动图。该应用程序永远不会失去焦点。
这是一个显示发生了什么的日志
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}]
在此之后运行这里是再次调用的对象
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}]
为什么这些值会消失?我可以用不同的方式来解决这个问题吗?我试过使用单例并传递可序列化的结果相同。 提前致谢!
我终于明白这个问题是什么问题了
JAVA是传值
每当我创建新对象时,我的自定义对象都会传递散列图的值。然后我会编辑对象或调用它,哈希图将 return 它的最后一个 key/value 对。我通过使用 Gson 序列化 hashmap 并稍后 return 将其转换为它的形式解决了这个问题。