我正在使用Parcelable接口将我的对象传递给片段。根据Android的文档,它是“一个类的接口,其实例可以写入并从包中恢复”[1]。
我期待每次ParcelableObject通过Bundle传递到另一个片段时,对象被写入Parcel,然后Parcelable.CREATOR应该重新创建对象并初始化对象的变量。
如果我将我的parcelable对象(X)放入Bundle并将此包设置为我的新片段的参数,这对我来说有点意外。然后我在新片段的onCreateView方法中从bundle中读取了我的parcelable对象(Y)。我在onCreateView(Y)中得到的对象与我在前一个片段中放入Bundle的那个(X)相同(意思是X == Y)。更令人惊讶的是,Parcelable.CREATOR甚至没有被调用
他们在Android的关于Bundle的文档中写道:“从String值到各种Parcelable类型的映射。” [2]。好吧,这可能是什么解释了为什么书面对象与读取对象相同,但为什么他们需要Parcelable.CREATOR接口,即使没有它也能正常工作?
现在让我们更具体一点:
我有ParentPagerFragment
,其中包含一个ViewPager,它是3 ChildTextViewFragment
以下是ParentPagerFragment
impl的重要部分。
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_pager, container, false);
List<ChildTextViewFragment> viewFragments = new ArrayList<>();
MyEntity mEntity1 = new MyEntity();
mEntity1.setId(1l);
MyEntity mEntity2 = new MyEntity();
mEntity2.setId(2l);
MyEntity mEntity3 = new MyEntity();
mEntity3.setId(3l);
viewFragments.add(ChildTextViewFragment.newInstance(mEntity1));
viewFragments.add(ChildTextViewFragment.newInstance(mEntity2));
viewFragments.add(ChildTextViewFragment.newInstance(mEntity3));
MyPagerAdapter mPagerAdapter = new MyPagerAdapter(getChildFragmentManager(), viewFragments);
ViewPager mViewPager = (ViewPager) v.findViewById(R.id.pager);
mViewPager.setAdapter(mPagerAdapter);
return v;
}
ChildTextViewFragment
仅显示简单的TextView
ChildTextViewFragment::newInstance implementation
public static ChildTextViewFragment newInstance(MyEntity mEntity) {
ChildTextViewFragment fragment = new ChildTextViewFragment();
Bundle bundle = new Bundle();
Log.d(MyEntityParcelable.TAG, "ChildTextViewFragment::newInstance : creating Parcelable : mEntity has ID = "+ mEntity.getId() +" mEntity = " + mEntity);
MyEntityParcelable entityPar = new MyEntityParcelable(mEntity);
bundle.putParcelable(M_ENTITY_KEY, entityPar);
fragment.setArguments(bundle);
return fragment;
}
ChildTextViewFragment::onCreateView implementation
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_text, container, false);
TextView mTextView = (TextView) view.findViewById(R.id.textView1);
MyEntityParcelable mEntityPar = getArguments().getParcelable(M_ENTITY_KEY);
MyEntity mEntity = mEntityPar.getMyEntity();
Log.d(MyEntityParcelable.TAG, "ChildTextViewFragment::onCreateView : reading Parcelable : mEntity has ID = "+mEntity.getId()+" mEntity = " + mEntity);
mTextView.setText("my id is: " + Long.toString(mEntity.getId()));
return view;
}
myEntity所:
public class MyEntity {
private long id;
private String name;
private String description;
private String owner;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
}
MyEntityParcelable
public class MyEntityParcelable implements Parcelable {
public static final String TAG = "PARCELABLE_TESTING";
private MyEntity myEntity;
public MyEntityParcelable(MyEntity mEntity) {
this.myEntity = mEntity;
}
private MyEntityParcelable(Parcel in) {
Log.d(TAG, "MyEntityParcelable::Parcel constructor : creating MyEntity from Parcel");
myEntity = new MyEntity();
myEntity.setId(in.readLong());
myEntity.setName(in.readString());
myEntity.setDescription(in.readString());
myEntity.setOwner(in.readString());
}
@Override
public int describeContents() {
return this.hashCode();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
Log.d(TAG, "MyEntityParcelable::writeToParcel : writing myEntity with ID = " + myEntity.getId() + " to Parcel");
dest.writeLong(myEntity.getId());
dest.writeString(myEntity.getName());
dest.writeString(myEntity.getDescription());
dest.writeString(myEntity.getOwner());
}
/*
* Parcelable interface must also have a static field called CREATOR, which
* is an object implementing the Parcelable.Creator interface. Used to
* un-marshal or de-serialize object from Parcel.
*/
public static final Parcelable.Creator<MyEntityParcelable> CREATOR = new Parcelable.Creator<MyEntityParcelable>() {
public MyEntityParcelable createFromParcel(Parcel in) {
return new MyEntityParcelable(in);
}
public MyEntityParcelable[] newArray(int size) {
return new MyEntityParcelable[size];
}
};
public MyEntity getMyEntity() {
return myEntity;
}
}
正如我上面提到的,PARCELABLE.CREATOR甚至没有被调用,这里是Log演示控制流程。
13:55:14.946: ChildTextViewFragment::newInstance : creating Parcelable : mEntity has ID = 1 mEntity = com.example.nestedfragments.MyEntity@21208247
13:55:14.951: ChildTextViewFragment::newInstance : creating Parcelable : mEntity has ID = 2 mEntity = com.example.nestedfragments.MyEntity@1ecfc4f8
13:55:14.952: ChildTextViewFragment::newInstance : creating Parcelable : mEntity has ID = 3 mEntity = com.example.nestedfragments.MyEntity@3c4a9dd1
13:55:15.069: ChildTextViewFragment::onCreateView : reading Parcelable : mEntity has ID = 1 mEntity = com.example.nestedfragments.MyEntity@21208247
13:55:15.071: ChildTextViewFragment::onCreateView : reading Parcelable : mEntity has ID = 2 mEntity = com.example.nestedfragments.MyEntity@1ecfc4f8
13:55:33.614: ChildTextViewFragment::onCreateView : reading Parcelable : mEntity has ID = 3 mEntity = com.example.nestedfragments.MyEntity@3c4a9dd1
请注意,对象标识在创建和阅读时是相同的。
这是在片段之间传递对象的正确方法吗? 在哪种情况下,Parcelable.CREATOR接口称为?
谢谢你的帮助!
答案 0 :(得分:2)
那么可能是什么原因解释了为什么写入的对象与读取对象相同,但为什么即使没有它也需要Parcelable.CREATOR接口才能正常工作?
您的Parcelable
未被放入Parcel
,因此Parcelable.CREATOR
未被使用。
Parcel
涉及IPC。因此,如果您尝试通过Intent
传递相同的startActivity()
,那将涉及您的CREATOR
,因为startActivity()
涉及IPC。
配置更改可能涉及Parcel
(他们可能会优化此方案)。如果您的流程在后台终止,并且用户通过最近任务列表快速返回到正在运行的任务,则会涉及Parcel
和CREATOR
。