16

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

在 Android 4 中,您可以调用setRetainInstance(true)aFragment以便在配置更改(这基本上意味着设备旋转)时,Fragment不会破坏 java 对象并且不会创建它的新实例。即,保留实例。

这比在 Android 1-3 中更加理智且不那么令人恼火,因为您不必处理和捆绑所有数据,因此可以将其传递给新的(或)实例,然后再次解除捆绑。这基本上是您期望发生的事情,并且可以说它应该如何从一开始就为 s 工作。onRetainNonConfigurationStateInstance()FragmentActivityActivity

正如您所期望setRetainInstance(true)的那样,视图也会在旋转时重新创建(被称为)。onCreateView()我假设(未经测试)资源解析(layoutvs layout-land)有效。

所以我的问题有两个:

  1. 为什么不是Activities一开始就这样。
  2. 为什么这不是默认值?有没有什么理由让你真的希望你Fragment轮换中被毫无意义地摧毁和重建?因为我什么都想不出来。

编辑

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

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;
    }
}
4

2 回答 2

13

以便在配置更改时(这基本上意味着设备旋转)

以及更改语言环境、更改 SIM 卡、更改默认字体大小、插入或移除外部键盘、将设备放入扩展坞或从中移除等。

您不必处理 onRetainNonConfigurationState()

那就是onRetainNonConfigurationInstance()

捆绑所有数据,以便将其传递给新的 Fragment(或 Activity)实例,然后再次解绑

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

而且我假设(未经测试)资源解析(布局与布局土地)有效。

正确的。

是否有任何理由让您真正希望您的 Fragment 被无意义地销毁并在轮换时重新创建?

当然。

正如您所注意到的,所有小部件都被重新创建,因此与小部件绑定的数据成员不仅不需要保留。除非您以某种方式专门将它们重置null为保留的片段,直到onCreateView()再次调用,这些数据成员将保留旧的小部件,这些小部件将保留旧的活动实例,这将防止旧的活动实例被垃圾收集。AFAIK,onCreateView()直到片段将被重新显示之前不会被调用,这可能不会在很长一段时间内(片段未用于新方向,或者片段用于某个页面中的某个页面)ViewPager用户以旧方向访问但未在新方向重新访问等)。这意味着保留的片段可能会在相当长的一段时间内保留旧的活动对象。根据该活动可能持有的其他内容Bitmap(例如,大型对象),这可能很糟糕。

类似地,一个片段本身包含大数据,在配置更改后可能会或可能不会使用该片段,是不应该保留的片段。

此外,还会有一些片段根本不需要保留(例如,所有数据都由 填充Loaders,它们已经知道配置更改并适当地处理它们)。

等等。

就垃圾收集问题而言,默认不保留片段是最安全的做法。您可以选择保留一些片段,但您有责任确保您不会因此而搞砸自己。

于 2012-09-19T11:32:06.450 回答
0

我不知道第一个问题的答案。从一开始就应该是这样的。我猜谷歌的某个人认为他们非常聪明地提出了这个方案。

然而,第二个问题要容易得多。这不是默认设置,因为这不是 Android 开发所期望的。Android 开发人员知道实例会在轮换时死掉并期待它。更改默认设置会让很多开发人员非常生气。

于 2012-09-19T11:07:51.393 回答