Android 为什么我会想要“setRetainInstance(false)”或-处理设备旋转的正确方法

Android 为什么我会想要“setRetainInstance(false)”或-处理设备旋转的正确方法,android,android-activity,rotation,fragment,lifecycle,Android,Android Activity,Rotation,Fragment,Lifecycle,如果我在这些问题上有错,请纠正我。这是一个澄清问题,因为我还没有在任何地方看到它的明确写法 在安卓4中,您可以对片段调用setRetainInstance(true),以便在配置更改时(基本上意味着设备旋转),不会破坏片段java对象,也不会创建它的新实例。也就是说,实例被保留 这比安卓1-3更理智,也不那么恼火,因为你不必处理重新配置状态实例()并打包所有数据,这样它就可以被传递到新的片段(或活动)实例,只需再次解包。这基本上就是你期望发生的事情,也可以说是它从一开始就应该如何在活动中起作用

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

在安卓4中,您可以对
片段
调用
setRetainInstance(true)
,以便在配置更改时(基本上意味着设备旋转),不会破坏
片段
java对象,也不会创建它的新实例。也就是说,实例被保留

这比安卓1-3更理智,也不那么恼火,因为你不必处理
重新配置
状态
实例()
并打包所有数据,这样它就可以被传递到新的
片段
(或
活动
)实例,只需再次解包。这基本上就是你期望发生的事情,也可以说是它从一开始就应该如何在
活动中起作用

使用
setRetainInstance(true)
时,视图也会像您预期的那样在旋转时重新创建(
onCreateView()
)。我假设(未测试)资源分辨率(
layout
vs
layout land
)有效

所以我的问题有两个:

  • 为什么
    活动从一开始就不是这样
  • 为什么这不是默认值?你有没有任何理由希望你的
    片段在旋转时被无意义地销毁和重新创建?因为我想不出有什么
  • 编辑 为了澄清我将如何做:

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

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

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

    因此,在配置更改时(基本上意味着设备旋转)

    以及更改区域设置、更改SIM卡、更改默认字体大小、插入或移除外部键盘、将设备放入坞中或从坞中移除等

    您不必处理onretainonconfigurationstate()

    这就是onRetainonConfiguration实例()

    将所有数据打包,这样就可以将其传递到新的片段(或活动)实例,而只需再次进行拆分

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

    我假设(未测试)资源分辨率(布局与布局土地)有效

    你有没有任何理由希望你的碎片在旋转时被毫无意义地销毁和重建

    当然

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

    类似地,一个本身保存在大数据上的片段(在配置更改后该片段可能会被使用,也可能不会被使用)也不应该被保留

    此外,还有一些片段不需要保留任何内容(例如,所有数据都由
    加载程序填充,这些加载程序已经知道配置更改并进行适当处理)

    等等


    对于垃圾收集问题,默认情况下不保留碎片是最安全的做法。您可以选择保留一些碎片,但您有责任确保这样做不会弄糟自己。

    修复某些东西会激怒开发人员,因为他们已经习惯了g坏了。真的吗?更改现有组件的行为肯定会激怒开发人员。不是那些听到此更改的热情开发人员,而是那些突然发现自己的代码不再适用于新版本SDK的“随机”开发人员。我想你们在谈论不同的事情:制作
    Act默认情况下,像这样工作显然是不可能的——那列火车很久以前就开走了。但他们只添加了片段和
    setRetainInstance()
    最近,他们本可以将其作为片段的默认设置。我猜,他们选择的是一致性,而不是一半的API正常,一半疯狂。片段是在安卓3.0中添加的,比4.0问世早了好几年。安卓3.0只有18个月了!也许你的意思是“好几个月”?:-)很多分!1.我从来没有在私有静态内部类中看到过任何片段捆绑数据,而且我经常使用Google的代码。你能提供一个他们推荐的链接吗?2.当
    onCreateView()时,视图成员变量(即
    mProgressView
    等)肯定会被覆盖