Android面试一天一题(5 Day)

作者: goeasyway | 来源:发表于2016-05-20 21:08 被阅读7044次

2009年冬天,北京寒风刺骨,我们公司组织到北京进行为期一周的Android开发培训,讲师来自荷兰的Hello9培训机构。让我印向深刻的是,说着极易让人打瞌睡的北欧英文的讲师,在给我们讲EditText控件时,说到在Activity转屏时EditText是不会保存状态的(即在EditText中输入字符,然后转屏,重建Activity后EditText之前输入的字符没有被保存)。为表示他的正确,他特意演示了一下,这一演示发现状态被保存了!后来他解释说是,在早期的SDK版本(1.6以前)确实是不会保存的,之后Android做了改进。

在我问面试者关于自定义View的问题时,常常会问他们关于保存View的状态的问题,如果对方不大清楚怎么做,我会认为面试者在自己定View上的经验不够,因为至少要知道可以在View的onSaveInstanceState中保存数据吧。

面试题:自定义View的状态是如何保存的?

Android有一套标准的做法,做过自定义View的人很容易遇到这个问题,因为Activity转屏,或Home键到后台很容易在被系统销毁,恢复时我们肯定是希望看到View保持之前状态。

提示:系统内存紧张时会主动销毁这类Activity,做为开发我们可以利用DDMS的stop process模拟这一动作而不必等到内存紧张时,如下图所示:


红色的STOP图标可以杀掉当前选择的进程

这个标准的做法可以随便从一个Android自带的控件中看到,如TextView的源代码(SavedState extends BaseSavedState)。

    /**
     * User interface state that is stored by TextView for implementing
     * {@link View#onSaveInstanceState}.
     */
    public static class SavedState extends BaseSavedState {
        int selStart;
        int selEnd;
        CharSequence text;
        boolean frozenWithFocus;
        CharSequence error;

        SavedState(Parcelable superState) {
            super(superState);
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(selStart);
            out.writeInt(selEnd);
            out.writeInt(frozenWithFocus ? 1 : 0);
        ......

BaseSavedState是View的一个内部静态类,从代码上我们也很容易看出是把控件的属性(如selStart)打包到Parcel容器,Activity的onSaveInstanceState、onRestoreInstanceState最终也会调用到控件的这两个同名方法。

Parcel相关的问题以后专门再讲,现在我们可以焦点先放在状态保存上,先看一下Activity的状态如何保存的:

Activity 状态

注:无法保证系统会在销毁Activity前一定调用onSaveInstanceState,例如用户使用“返回” 按退出 Activity 时,因为用户的行为是在显式关闭 Activity,所以不会调用onSaveInstanceState。

如果系统调用onSaveInstanceState,那么它是在onStop还是在onPause之前执行呢?

可以肯定的是它会在调用 onStop之前,但是是不是在onPuase之前就不能确认了,要看情况,官方文档在说明这个执行顺序时用了“可能”这个词。

小结

Activity类的onSaveInstanceState默认实现会恢复Activity的状态,默认实现会为布局中的每个View调用相应的 onSaveInstanceState方法,让每个View都能保存自身的信息。

这里需要注意一个细节:想要保存View的状态,需要在XML布局文件中提供一个唯一的ID(android:id),如果没有设置这个ID的话,View控件的onSaveInstanceState是不会被调用的。

相关文章

  • Android面试一天一题-goeasyway

    以下文章作者:goeasyway Android面试一天一题(1 Day) Android面试一天一题(2 Day...

  • MS(1):Android之架构篇

    一、架构相关 1、MVC,MVP,MVVM MS思考:Android面试一天一题(Day 33:Android开发...

  • 面试题

    最全的BAT大厂面试题整理答案Android面试一天一题(Day 37:一套高级工程师的面试题)Android面试...

  • MS(2):Android之基础知识篇

    二、组件 1、Activity----------1 MS思考:Android面试一天一题(3 Day):Acti...

  • MS(7):非技术问题篇

    一、GM问非技术问题汇总 MS思考:Android面试一天一题(Day 34:常去的Android相关站点) 说下...

  • MS(3):Android之机制原理篇

    五、重点机制原理 1、Handler机制 MS思考:Android面试一天一题(8 Day):Handler相关分...

  • MS(5):android之进阶篇

    七、自定义View MS思考:Android面试一天一题(Day 30:老外的自定义View面试题)MS思考:老外...

  • android Service 一些思考

    看了Android面试一天一题(1 Day),对Service 的一些总结与思考 作者原文章链接: http://...

  • MS(6):Java篇

    MS思考:Android面试一天一题(7 Day):Java相关 1.Switch能否用string做参数? 在J...

  • 《Android面试一天一题》即将“剧终”

    我是去年5月开始写《Android面试一天一题》这个系列,到现在写了45篇,基本上涉及到Android面试的常见方...

网友评论

  • Mr_kvkk:activity其实比较少的..fragment就是这个问题会出bug的
  • 9377d65d6f1f:感谢楼主
  • 望北8261:那个模拟内存紧张,前提至少要有两个Activity,比如:Activity A,B,C,这时候点击stop,是会kill掉app,然后创建B,此时按返回键,会重新创建A。

    在AndroidStudio中的AndroidMonitor面板下那个Terminate Application按钮,有着同样的效果。
  • 203cbf399350:对于自定义View的知识了解太少了,感谢
  • 流穿枫:当连续打开多个activist,返回到后台后,如果因为内存紧张activity被回收,虽然会调用onSaveInstanceState保存状态。但是当再次打开APP时,总是先出现空白的actionbar和view,再出现之前的数据。 这需要1~2秒左右的时间。然后点击back,返回上一个activity,又是这样的情况。感觉体验很不友好。 我的处理是只要因为内存紧张被回收的,就直接kill掉APP,直接重启。。。 如果手机性能好,大多都不会因为内存紧张而被回收的。
  • ButterKnife:这个真的长知识了.这两个还正不知道setId和setSaveEnabled();
  • 天青色等煙雨_而我在等妳:就是说异常退出Activity会自动保存View的状态,用户主动退出不会自动保存是吧?

    那么如果想实现用户退出Activity也保存View状态呢?能利用View保存状态的机制呢?
    goeasyway:@天青色等煙雨_而我在等妳 嗯,主动按返回键退出是不会调用onSaveInstanceState的。“用户又要自己退出又要保存View状态”,这种可以考虑使用数据库或者SharedPreference来做了。存在onSaveInstanceSate数据并不是持久的,重启(或者一些情况发生)就没了。
  • YungFan:最后一个细节 还真不知道 设置了id就行了?
    天青色等煙雨_而我在等妳:看了下源码,确实是需要setId和setSaveEnabled();

    Controls whether the saving of this view's state is
    * enabled (that is, whether its {@link #onSaveInstanceState} method
    * will be called). Note that even if freezing is enabled, the
    * view still must have an id assigned to it (via {@link #setId(int)})
    * for its state to be saved.
    e13c67a94a46:@YungFan 自定义控件的时候还要设置setSaveEnabled(true)。
    MeloDev:@YungFan 恩是的,这是组件自身保存数据的特性
  • 0e52bf69a6de:最后一点之前确实没看到过,有时间测试下。感谢楼主,涨姿势了。
  • OvenChou:楼主你好 针对最后的注意 我有个疑问: 如果自定义的view通过new的创建的实例,会触发onSaveInstanceState方法么
    OvenChou:@steven_chan 重调这个方法只有设置唯一id么
    steven_chan:@周盼Oven 我觉得没有设置唯一ID应该不会吧
  • 盖小同学:感谢 长知识中…

本文标题:Android面试一天一题(5 Day)

本文链接:https://www.haomeiwen.com/subject/ghrvrttx.html