在某些活动中,我必须将MVC模型另存为可打包文件。这个可包裹的包裹是根据the doc构建的,我对它的阅读已经足够多了(但是谁知道,我显然可能错过了一些东西)。该活动存在漏洞,但我正在努力了解其原因。 SO问题Communication objects between multiple fragments in ViewPager很有趣,但是我的代码已经遵循了答案中的指导原则。
该活动拥有一个Viewpager,其中包含大约60个片段(但最多350个)。将模型从活动传递到所有片段,并将片段中的用户操作保存到模型中。
每当我暂停活动时,就会一次触发onSaveInstanceState
,并在多次触发包裹的writeToParcel
方法之后立即触发。触发器的数量取决于viewpager
+ 1中加载的片段数。因此,在活动启动时,如果我关闭仿真器然后再打开,writeToParcel
被调用3次(仅1次和1次)。如果加载了第2个片段),如果我向右滑动一次并再次执行,则调用4次(显示第2个片段,并加载第3个片段),如果我在适配器上setExtPosition()
并转到第10个片段,{ {1}}被调用7次(加载了9th,10th和11h)。
当然,如果我的用户轻扫每个片段,最终将得到一个丑陋的writeToParcel
,这将我带到这里。
这是一些代码。这里可能会有大量的代码/概念改进,非常欢迎任何提示,但是我的主要问题是我发现的这个肮脏的小泄漏。
在我的活动中:
TransactionTooLargeException
在我的片段中:
@Override
public void onSaveInstanceState (Bundle outState) {
outState.putParcelable("model", myParcelable);
super.onSaveInstanceState(outState);
}
在我的可包裹模型中:
public static MyFragment newInstance(Model model) {
MyFragment fragment = new MyFragment();
Bundle args = new Bundle();
args.putParcelable(KEY_MODEL, model);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
mModel = args.getParcelable(KEY_MODEL);
}
我在@Override
public void writeToParcel(Parcel dest, int flags) {
int startSize = dest.dataSize();
dest.writeString(foo); //one of these string is supposed to be null
dest.writeString(bar);
dest.writeString(foobar);
dest.writeByte((byte) (isMyObjectTrue ? 1 : 0));
dest.writeList(someStringList);
dest.writeList(someIntegerList);
dest.writeBundle(someBundle); //I use a Bundle to save a Map<String,String>
int endSize = dest.dataSize();
}
方法中运行了调试器,但我惊讶地发现writeToParcel()
永远不会为0。这正常吗?
我搜索了整个代码,仅在此活动和片段startSize
中调用putParcelable()
或任何名称可拆分的书写方法。
如何找到这种怪异的指数行为的原因?
PS:当然可以要求更多代码。
我已经实现了@Ben P.建议的解决方案,该问题已得到很大改善,但尚未完全解决。我的活动实现了一个接口,该接口现在具有在newInstance()
中调用的getModel()
方法,并且使用了onAttach()
从片段更新模型。片段的setUserInput(char userInput)
方法不再保存模型。
MyFragment
newInstance()
这把指数问题变成了线性问题,这显然更好,但仍然是一个问题。
现在,@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
callBack = (MyInterface) context; //callBack is a class field
mModel = callBack.getModel(); //mModel too
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement MyInterface");
}
}
仅被调用一次,但是总包裹大小仍随着装入的物品数而增加。根据{{1}}的测量,我的模型在包裹内大约占3kb(+/- 10%,取决于输入的数量)。
我怎么知道增长来自哪里?
答案 0 :(得分:1)
在具体讨论您的问题之前,我想指出传递给Bundle
的{{1}}是片段实例状态的一部分。每次销毁并重新创建一个片段时,都必须保留这些参数。因此,您在setArguments()
中添加的任何内容都有可能在配置更改期间被打包和取消打包。
该活动拥有一个Viewpager,其中包含大约60个片段(但最多350个)。将模型从活动传递到所有片段,并将片段中的用户操作保存到模型中。
这听起来像您有一个Bundle
对象,所有片段都共享。如果是这种情况,我建议不将模型对象作为其参数Model
的一部分传递给每个片段。保存和还原实例状态时,这样做将导致大量重复。相反,我会在您的Bundle
中公开一个方法(类似Activity
),然后从您的片段中调用该方法以检索模型实例。
另一方面,听起来您可能只是从同一对象getModel()
开始 ,并且每个片段都可以以某种方式对其进行突变。这意味着您要做必须为每个片段保存一些东西到实例状态...但是您可以在这里进行优化。不必保存和还原整个Model
对象,您可以只存储差异。也就是说,如果片段#1更改了模型的Model
,而片段#2更改了模型的name
,那么您可以让片段#1仅保存新名称,让片段#2仅保存新名称。值。这样做而不是保存两个额外的模型对象副本,可能会节省大量资金。