Android何时序列化对象?

时间:2015-06-19 10:14:35

标签: java android android-fragments serialization pass-by-reference

我正在处理Android项目,我想将自定义类MainActivityModel传递给FragmentMainActivityPlaceholderFragment

我已将MainActivityModel序列化:

public class MainActivityModel implements Serializable{

    public int current = 0;
    public int pageCount = 0;

    public boolean pristine = true;

    // Stores the fetched dataMap
    public ArrayList<HashMap<String, String>> arrayList;

    public MainActivityModel() {
        this.arrayList = new ArrayList<>();
    }

    public String getCategory() {
        return Util.categories[current];
    }

    public CharSequence getmTitle () {
        return  Util.toTitleCase(
                Util.mapCategoryPretty(Util.categories[current]));
    }
}

我将它传递给Fragment,就像这样:

public static MainActivityPlaceholderFragment newInstance(MainActivityModel mainActivityModel) {
    MainActivityPlaceholderFragment fragment = new MainActivityPlaceholderFragment();
    Bundle args = new Bundle();
    args.putSerializable(ARG_DATA_MODEL, mainActivityModel);
    fragment.setArguments(args);
    Log.v(LOG_TAG, "Created: " + mainActivityModel.getmTitle());
    return fragment;
}

我这样访问:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mainActivityModel = (MainActivityModel) getArguments().getSerializable(ARG_DATA_MODEL);
    mMainActivityPlaceholderFragmentView = new MainActivityPlaceholderFragmentView(this, mainActivityModel);

    mCallbacks.onPlaceholderFragmentCreated(mainActivityModel.current);
}

我最初认为(在阅读下面提到的答案之后),序列化将数据转换为字节并在需要时随后恢复它们。所以我的对象将被复制。如果我只想访问数据,这是可以的。但我也想从片段中修改实际模型(在MainActivity中引用)。

要进行实验,我在片段中将pristine设置为false,并将其记录在MainActivity中,这确实是错误的。

但如果序列化是按值传递的,那么这是怎么回事?

我读过的内容:

  1. What is object serialization?
  2. R: Pass by reference
  3. what is Serializable in Java
  4. What is serialization in Java?

4 个答案:

答案 0 :(得分:3)

Serializable对象的引用仍然是对象引用,它与传递List对象或Foo对象没有什么不同。令人困惑的部分是 if 序列化发生。

来自android.app.Fragment.setArguments(Bundle)的文档:

  

此处提供的参数将在片段销毁和创建中保留。

有两种方法可以实现这一目标:

  • Bundle仅存储原始字节,并为每个get / put操作序列化/反序列化。
  • 允许Bundle保存活动对象,并要求它在需要销毁/重新创建片段时序列化/反序列化所有内容。

显然,第一个选项非常效率低下:get / put操作比活动/片段生命周期更改频繁得多。因此,Android只会在生命周期更改时序列化/反序列化

这会导致您的用例中出现“怪异”行为。您假设Serializable对象已由Bundle立即序列化 ,而Bundle只是保留对您的对象的引用。由于片段未在newInstanceonCreate调用之间被销毁,因此您看到完全相同的Bundle包含完全相同的引用。

当然,您应该不依赖对这些引用保持不变。每当您的应用程序被要求保持其状态时(例如,当转到后台,旋转屏幕时,或系统需要释放RAM时),这些对象将被序列化并且引用已经消失。将从序列化数据重新创建对象,但它们将具有不同的引用。

答案 1 :(得分:0)

在Java中,所有对象都通过引用传递,只有基本类型(int,float,long ...)按值传递。

我真的不知道Serializable是如何工作的,但是如果它转换为不是基本类型的byte []那么这就是它工作的原因。

如果你将一个Serializable类写入一个文件并将其打开为ASCII,你会看到一种递归的toString(),然后可能是数据作为字节。

希望这有帮助。

答案 2 :(得分:0)

序列化会创建对象的深层副本,这意味着如果序列化然后反序列化包含其他对象的对象,您将获得新的独立对象(带有新引用),所有内容的副本,绝对不会引用您仍然拥有的对象在堆上。因此,如果修改刚刚反序列化的对象,则只能修改这些对象,而不能修改堆上可能存在的任何引用。

如果你想重新调整你刚刚用内存中的对象反序列化的引用,你必须对它进行编码。

答案 3 :(得分:0)

您描述的行为看起来很像Parcel active objects,而不是sun-java风格的序列化。