activity/fragment view的保存恢复

本文详细介绍了在Android开发中如何保存和恢复Activity及Fragment的状态。包括自动保存View状态的机制,以及如何手动保存Activity和Fragment的成员变量。强调了设置android:id的重要性,以及在使用第三方自定义组件时需注意的事项。

保存/恢复 activity和fragment

一、activity

当Activity的onSaveInstanceState被调用的时候,Activity将会从View 层次(View Hierachy)中的每一个View中自动搜集View的状态。请注意,只会搜集实现了View状态保存/恢复的内部方法的View的数据。一旦onRestoreInstanceState被调用,Activity将会将这些搜集到的数据一对一的返还给View 层次里在搜集的时候提供了同样的android:id属性的View。

这就是为什么尽管Activity已经被销毁,而我们并没有做一些特别的事情来保存状态,但是EditText中键入的文本仍然能够呈现的原因。这并不是什么魔法,这些View 的状态已经被自动的保存和恢复回来了。

这也是为什么View 在没有被设置android:id属性的时候不能保存和恢复自己的状态的原因。

尽管这些View 的状态被自动的保存了,但是Activity的成员变量并不会有同样的效果。这些成员变量会被和Activity一起销毁。你可以手动的保存和恢复它们,通过onSaveInstanceStateonRestoreInstanceState方法。

public class MainActivity extends AppCompatActivity {

    // These variable are destroyed along with Activity
    private int someVarA;
    private String someVarB;

    ...

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("someVarA", someVarA);
        outState.putString("someVarB", someVarB);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        someVarA = savedInstanceState.getInt("someVarA");
        someVarB = savedInstanceState.getString("someVarB");
    }

}

 

二、fragment

一旦Fragment从后退栈中返回,它的View 会被销毁,并重新创建。

这种情况下,Fragment并不会被销毁,只有Fragment中的View 会被销毁。 结果是,并不会发生任何实例状态的保存。但是上面展示的这些View在Fragment生命周期中被重新创建时,发生了什么?

别惊讶,因为Android是这样设计的。在这种情况下,Fragment中的View 状态的保存/恢复会被内部调用。结果就是,每一个实现了内部View 状态保存/恢复的View ,将会被自动的保存并且恢复状态,例如带有android:freezeText="true"属性的EditText或者TextView。就之前完美显示的一样。

请注意,在这种情况下,只有View 被销毁(并重建)了。Fragment仍然在这里,就像它内部的成员变量一样。所以你不需要对它们做任何事情。不需要任何额外的代码。

 

public class MainFragment extends Fragment {

    // These variable are destroyed along with Activity
    private int someVarA;
    private String someVarB;

    ...

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("someVarA", someVarA);
        outState.putString("someVarB", someVarB);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        someVarA = savedInstanceState.getInt("someVarA");
        someVarB = savedInstanceState.getString("someVarB");
    }

}

如果Fragment中的每一个View 都在内部实现了View 的状态的保存和恢复.在这种情况下,你就没有必要做任何事情,View 状态会被自动的恢复,并且Fragment中的成员变量也和之前的一样。

所以Fragment状态保存/恢复最佳实践的第一条件就是...

你应用中使用的每一个单独的View都必须在内部实现状态的保存和恢复

Android内部通过onSaveInstanceStateonRestoreInstanceState 方法提供了保存和恢复View 状态的机制。开发者的任务就是实现它。

基本上来说,每一个单独的Android提供的的标准View 组件都已经在内部完成了这些事情,例如EditText,TextView,Checkbox.
尽管也许你手动让它生效,例如,你需要为TextView设置android:freezeText为true,来使用这个功能。

但是如果我们讨论关于互联网上贡献的第三方的自定义组件。我必须说,它们大多数都没有实现这部分的代码,在使用中会导致很大的问题。

如果你决定使用第三方的自定义组件,你不得不确保它已经在内部实现了View 的保存和恢复,否则你必须创建继承这个三方组件的一个派生的子类,并且自己实现onSaveInstanceStateonRestoreInstanceState方法。

并且不要忘记为每一个你需要开启View状态保存和恢复的View设置android:id属性,不然它们的状态不能正确的恢复。

 

 

 

 

 

 

 

 

 

 

在 Android 开发中,**Activity/Fragment 的生命周期** 与 **View 的生命周期** 是两个密切相关但职责不同的概念。理解它们的执行顺序和交互时机,对于正确实现 UI 控制(如骨架屏、动画、数据绑定等)至关重要。 --- ### 一、Activity 生命周期 ```kotlin onCreate() → onStart() → onResume() → onPause() → onStop() → onDestroy() ``` - `onCreate()`:创建 Activity,通常进行 `setContentView()` 和初始化组件。 - `onStart()`:界面即将可见(但还未获得焦点)。 - `onResume()`:界面可见且可交互。 - `onPause()` / `onStop()` / `onDestroy()`:对应暂停、不可见、销毁。 > ✅ 大多数 UI 初始化操作(如 `initView`, `initData`)放在 `onCreate()` 中。 --- ### 二、Fragment 生命周期 ```kotlin onAttach() → onCreate() → onCreateView() → onViewCreated() → onStart() → onResume() → onPause() → onStop() → onDestroyView() → onDestroy() → onDetach() ``` 关键点: - `onCreateView()`:inflate 布局,返回 root view。 - `onViewCreated()`:视图已创建完成,适合做 `findViewById`、设置监听器、观察 LiveData。 - `onDestroyView()`:视图被销毁(但 Fragment 实例仍存在),需解绑 View 相关引用(避免内存泄漏)。 --- ### 三、View 的生命周期(以自定义 View 为例) 虽然没有官方明确定义的“生命周期”方法,但以下回调是 View 生命周期的重要组成部分: 1. **构造函数** ```java public MyView(Context context, AttributeSet attrs) ``` - View 被实例化时调用。 2. **onFinishInflate()** - XML 布局填充完成后调用(适用于复合 View)。 3. **onAttachedToWindow()** - 当 View 添加到窗口时调用(可开始动画、注册监听)。 - 对应于 Activity 的 `onResume()` 后不久。 4. **onMeasure(int, int)** - 测量阶段,决定 View 的尺寸。 5. **onLayout(boolean, int, int, int, int)** - 布局阶段,确定子 View 的位置。 6. **onDraw(Canvas)** - 绘制阶段,使用 Canvas 绘图。 7. **onDetachedFromWindow()** - View 从窗口移除时调用(应停止动画、取消注册监听)。 > ⚠️ 注意:一个 View 只有在被添加到 Window 上后才会触发 `onAttachedToWindow()`,即使它的 parent 已经 inflate。 --- ### 四、三者关系与执行顺序(典型场景) 假设你在 Activity 的 `onCreate()` 中设置了布局: ```kotlin override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 触发 layout inflation } ``` 执行顺序如下: | 阶段 | 方法 | |------|------| | 1 | Activity.onCreate() | | 2 | LayoutInflater 解析 XML | | 3 | 自定义 View 构造函数执行 | | 4 | 自定义 View.onFinishInflate() | | 5 | Activity.onCreate() 继续执行 | | 6 | 视图树构建完成 | | 7 | Activity.onStart() | | 8 | Activity.onResume() | | 9 | View.onAttachedToWindow() (当真正 attach 到 window)| | 10 | View.onMeasure() → onLayout() → onDraw() | 📌 特别注意: - `onAttachedToWindow()` 可能会在 `onResume()` 之后才触发。 - 如果你在 `onCreate()` 就调用 `view.getWidth()`,可能为 0 —— 因为测量尚未完成。 --- ### 五、如何结合骨架屏设计? 根据你之前提到的骨架屏插入点: ```kotlin onCreate() ├── initView() // inflate 主布局 + 显示 skeleton ├── showSkeleton() // 控制 visibility 或 addView ├── initData() // 发起请求 └── observe(data) // 数据回来后 hideSkeleton(), bindData() ``` 此时你要知道: - `initView()` 中拿到的 View 已经 inflate 完成,但不一定已经 `onLayout` 过。 - 骨架屏展示可以在 `onViewCreated()`(Fragment)或 `onCreate()`(Activity)完成。 - 真正隐藏骨架屏应在数据加载完成且主线程空闲后(确保 UI 可渲染)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值