Parcelable接口是否持久保存对象引用? &安培; Parcelable.CREATOR没有被调用?

时间:2015-06-29 12:10:56

标签: android android-fragments parcelable parcel

我正在使用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接口称为?

谢谢你的帮助!

1 个答案:

答案 0 :(得分:2)

  

那么可能是什么原因解释了为什么写入的对象与读取对象相同,但为什么即使没有它也需要Parcelable.CREATOR接口才能正常工作?

您的Parcelable未被放入Parcel,因此Parcelable.CREATOR未被使用。

Parcel涉及IPC。因此,如果您尝试通过Intent传递相同的startActivity(),那将涉及您的CREATOR,因为startActivity()涉及IPC。

配置更改可能涉及Parcel(他们可能会优化此方案)。如果您的流程在后台终止,并且用户通过最近任务列表快速返回到正在运行的任务,则会涉及ParcelCREATOR