为什么我会想`setRetainInstance(false)`? – 或者 – 处理设备旋转的正确方法

如果我错了,请纠正我的错误。 这是一个澄清的问题,因为我没有看到它明确写在任何地方。

在Android 4中,您可以在Fragment上调用setRetainInstance(true) ,以便在configuration更改(基本上意味着设备旋转)时, Fragment java对象不会被销毁,并且不会创build新的实例。 也就是说,该实例被保留。

这比Android 1-3更加清醒,不那么令人onRetainNonConfiguration因为你不必处理onRetainNonConfiguration State Instance()并且捆绑所有的数据,所以只能传递给新的Fragment (或者Activity )实例再次解包。 这基本上是你所期待的,可以说从一开始它就应该如何为Activity

使用setRetainInstance(true) ,视图也会像您期望的那样重新创build( onCreateView()被调用)。 我假设(未testing)资源分辨率( layout vs layout-land )的作品。

所以我的问题是双重的:

  1. 为什么从一开始就没有这样的Activities呢?
  2. 为什么这不是默认? 你有没有任何理由,你真的希望你的Fragment被无意中销毁和重新创build轮换? 因为我想不出来

编辑

澄清我将如何做到这一点:

 class MyFragment extends Fragment { // All the data. String mDataToDisplay; // etc. // All the views. TextView mViewToDisplayItIn; // etc. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); mDataToDisplay = readFromSomeFileOrWhatever(); // Ignoring threading issues for now. } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.my_fragment, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { // At this point if mViewToDisplayItIn was not null, the old one will be GC'd. mViewToDisplayItIn = view.findViewById(R.id.the_text_view); mViewToDisplayItIn.setText(mDataToDisplay); } // Optionally: @Override public void onDestroyView() { // All the view (and activity) to be GC'd. mViewToDisplayItIn = null; } } 

Related of "为什么我会想`setRetainInstance(false)`? – 或者 – 处理设备旋转的正确方法"

所以在configuration改变时(基本上是指设备旋转)

更改语言环境,更改SIM卡,更改默认字体大小,插入或移除外部键盘,将设备放入底座或从中取出等等。

你不必处理onRetainNonConfigurationState()

这是onRetainNonConfigurationInstance()

将所有数据捆绑在一起,以便将其传递给新的Fragment(或Activity)实例,以便再次解除绑定

你的数据应该已经被“捆绑”(例如,私有静态内部类的实例),因此它不需要被“捆绑”或“解绑”。 另外,它经常不应该是“所有的数据”,除非你是内存泄漏的粉丝。

我假设(未testing)资源分辨率(布局vs布局土地)的作品。

正确。

是否有任何理由为什么你实际上希望你的片段被无意中销毁和重新创build轮换?

当然。

正如你所看到的,所有的小部件都是重新创build的,所以绑定到小部件的数据成员不仅不必保留。 除非你专门重置那些保留的片段null ,直到再次调用onCreateView() ,这些数据成员将保持旧的小部件,这将保存在旧的活动实例,这将阻止旧的活动实例垃圾集。 AFAIK, onCreateView()不会被调用,直到要重新显示片段,这可能不是很长一段时间(该片段不是在新的方向使用,或片段是在ViewPager中的某个页面用户以旧的方向访问,但不以新的方向重新访问等)。 这意味着保留的片段可以保留旧的活动对象很长一段时间。 根据还有哪些活动可能保留(例如,大的Bitmap对象),这可能是不好的。

类似地,一个片段本身保存在大型数据上,这个片段在configuration改变之后可能被使用也可能不被使用,是一个不应该被保留的片断。

此外,还会有一些简单地没有任何需要保留的碎片(例如,所有的数据都被Loaders填充,这些Loaders已经知道configuration的变化并且适当地处理它们)。

等等。

对于垃圾收集问题,不保留碎片的默认行为是最安全的行为。 你可以select保留一些片段,但是有责任确保你没有这样做。

我不知道第一个问题的答案。 从一开始就应该是这样的。 我猜Google有人觉得他们真的很聪明,想出这个scheme。

然而,第二个问题要容易得多。 这不是默认的,因为这不是Android开发所学到的东西。 Android开发知道实例就轮到死了,期待它。 改变默认值会让很多开发者真的生气。