当一个片段被替换并放回堆栈(或删除)时,它是否会保留在内存中?

行为是否类似于 Activity 的工作方式? 例如,对于 Activity,它的工作方式如下:

活动 A 启动 活动 B,而 B在屏幕上,如果系统需要,系统能够从内存中删除 A。在按回,A将被重新创建到内存中,就好像它从来没有离开在第一个地方。

我一直在寻找一个关于片段在记忆方面发生了什么的清晰解释,但是一无所获。工作原理是一样的吗?例如:

活动 C 在其布局中有 碎片 F。然后,在某些时候,F片段 G取代,但是 F被保留在它的回栈中。

F会留在内存中直到 C被杀死还是系统可以根据需要移除它?

我真正要问的是,如果我在一个活动中有一个复杂片段的后备堆栈,我是否会冒内存不足的风险?

40608 次浏览

Developer.android.com/guide/topics/fundamentals/fragments.html

片段必须始终嵌入到活动中,并且片段的生命周期直接受到宿主活动的生命周期的影响。例如,当活动暂停时,其中的所有片段也会暂停,当活动被销毁时,所有片段也会暂停。但是,当一个活动正在运行时(它处于恢复的生命周期状态) ,您可以独立地操作每个片段,例如添加或删除它们。当执行这样一个片段事务时,还可以将其添加到由活动管理的回堆栈中ーー活动中的每个回堆栈条目都是发生的片段事务的记录。后台堆栈允许用户通过按 BACK 按钮逆转片段事务(向后导航)。

我很抱歉不能提供给你一些官方的信息来源,但我也很好奇,看看会发生什么,并决定测试它。根据我的测试,是的,您冒着内存不足的风险。

我不得不在 for 循环中添加数量惊人的碎片(超过100个) ,以使 OutOfMemoryError发生,但它确实发生了。检查我的日志,我可以看到 onCreate()onCreateView()方法被调用了很多次,但是 onSaveInstance()onPause()onDestroy根本没有被调用。

作为参考,下面是我如何将片段添加到回栈中的:

getSupportFragmentManager().beginTransaction().add(R.id.scene_fragment_container, mSceneFragment).addToBackStack("FOOBAR").commit();

我添加的片段有些简单: 一个 ImageView,一个 EditText,一对 TextViews,一个 SeekBar和一个 ListView

但是,除非您在内存中持有大量数据,否则这不应该是一个问题。

后来,我试图只添加50到回堆栈,关闭应用程序,并重新启动它。正如我所希望/猜测的那样,所有的片段都被恢复了(并且调用了 onSaveInstance()onPause()方法) ,因此我的生命周期实现不是导致 OutOfMemoryError失效的问题。

看看这个: BackStackRecord 操作系统片段

这就是片段存储在后面堆栈中的方式。注意实时引用,这里既没有使用 WeakReference,也没有使用 SoftReference

现在这个: MBackStack

这是经理存储回栈的地方。简单的 ArrayList,也没有 WR 或 SR。

最后是 活动,片段

这是对片段管理器的引用。

GC 只能收集没有活动引用(不能从任何线程访问)的对象。这意味着,直到你的活动被摧毁(因此,FragmentManager参考消失了) ,GC 将无法收集回栈中的任何碎片

请注意,当 Activity 被销毁和 保持原状(就像你将设备转换到横向模式)时,它不会在栈中保留实际的 Fragment对象,只保留它们的状态—— 片段,片段状态对象,也就是说,每次用保留状态重新创建活动时,栈中的实际片段都会被重新创建。

希望这个能帮上忙。

因此,简而言之: 是的,通过将 Fragments添加到后台堆栈,可能会耗尽内存以及通过向视图层次结构添加太多的视图。

UPD 考虑到你的例子,F将保留在内存中,直到 C被杀死。如果 C被杀死,然后复活与不同的配置-F将被摧毁和转世在一个不同的对象以及。因此,在 C丢失状态或清除后台堆栈之前,F的内存占用一直存在。

是的,在一个活动中创建太多的片段可能会耗尽内存。只有当包含活动的。