Android笔记 Activity详解

1. 什么是Activity?

Activity作为Android四大组件之一,它有着举足轻重的地位。一般的情况下一个用户交互界面对应一个Activity,它为用户提供一个可视的界面,方便用户操作,比如说拔打电话、照相、发邮件或者是浏览地图等。

开发常用的Activity有 FragmentActivitiyListActivityPreferenceActivityTabAcitivty...如果界面有共同的特点或者功能的时候,还会自己定义一个BaseActivity

  1. 每一个Activity都会获得一个用于绘制其用户界面的窗口,一般情况下这个窗口会覆盖整个屏幕,但在某此情况下也会出现一些比屏幕小的窗口飘浮在另外一个窗口上面。Activity是一个view对象的容器,通过Window类的setContentView()方法添加到Activity上,最终提供与用户交互的界面;
  2. Activity是上下文对象 Context的子类, 并且实现了Window.callback,KeyEvent.callback 这两个接口,因此 Activity 可以响应和处理用户与窗口的交互事件,以及键盘相关的输入事件;
  3. 一个Android应用通常由一个或者多个Activity 组成;如果是多个Activity,一般会指定应用中的某个 Activity 为“主” Activity,即首次启动应用时呈现给用户的那个 Activity。 而且每个Activity 通过使用Intent(意图)均可启动另一个Activity,这里使用的是IPC机制
  4. 每次启动一个新的Activity 启动时,前一 Activity 便会停止,但系统会在回退桟中保留该 Activity,而新启动的Activity可以放在该栈顶,也可以设置其启动方式放入新的回退桟,这就和Activity四种启动方式有关了。(这里要了解 栈 Stack

附上一张图,对Activity有一个更直观和全面的认识: 这里写图片描述

image

对Activity有了一个比较直观的认识后,我们自然想到的是怎么使用它,其实对于Activity Google对其封装的还是挺厉害,开发者使用时主要就是继承Activity,通过setContentView()方法设置布局界面,然后重写它的几个生命周期函数;而跳转新的Acitivty更简单,通过一个Intent然后调用startActivity方法即可。

2.认识Activity生命周期

  • Activity几种状态

    Activity是通过回退桟来管理的,此时Activity可呈现出四种状态:

    • Running状态:一个新的Activity启动入栈后,它在屏幕最前端,处于栈的最顶端,此时它处于可见并可和用户交互的激活状态,可以用来响应用户的输入。
    • Paused状态:当Activity被另一个透明或者Dialog样式的Activity覆盖时的状态。此时它依然与窗口管理器保持连接,系统继续维护其内部状态,它仍然可见,但它已经失去了焦点,故不可与用户交互。
    • Stopped状态:当Activity不可见时,Activity处于Stopped状态。当Activity处于此状态时,一定要保存当前数据和当前的UI状态,否则一旦Activity退出或关闭时,当前的数据和UI状态就丢失了。
    • Killed状态:Activity被杀掉以后或者被启动以前,处于Killed状态。这是Activity已从Activity堆栈中移除,需要重新启动才可以显示和使用。

    4种状态中,Running状态和Paused状态是可见的(Running相当于Resumed),Stopped状态和Killed状态时不可见的(Killed相当于Destoryed)。

  • Activity生命周期

    在这里,才接触 Android 的人肯定有疑问,什么是生命周期。其实Activity的生命周期就像是人的一生,人从出生到成长,再到衰老,最后到死亡。Activity的生命周期跟人的一生相似,也有出生(创建)-成长(启动)-衰老(暂定)-死亡(销毁)的过程。

Android笔记 Activity详解_第1张图片

这个是Google官方给的一张示意图,这里面就详细介绍了一个Activity的声生命周期的每一个过程。

大体的流程是:onCreate() --> onStart() --> onResume() -->onPause() --> onStop() --> onDestroy();

  • Activity主要生命周期函数做介绍:
    1. void onCreate(Bundle savedInstanceState)
    • Activity生命周期的第一个方法,表示Activity正在被创建。当活动第一次启动的时候,触发该方法,可以在此时完成活动的初始化工作。比如:在该方法中通过setContentView 方法加载xml编写的布局文件,然后通过findByViewId方法获取控件。
    • onCreate()方法在Activity整个生命周期中只会调用一次,所以该方法中就可以做一些大致只需要做一次的工作,如:一些变量的初始化,资源的加载,初始化控件以及事件的绑定等。
    • 由于此时view还没有加载出来,因此该方法中不能开启动画的。
    • onCreate 方法有一个参数savedInstanceState,该参数可以为空(null ),也可以是之前调用 onSaveInstanceState ()方法保存的状态信息。

    注:onCreate()的官方文档注释,建议 setContentView()、findViewById() 在 onCreate() 中调用,但在onStart()中调用 setContentView()、findViewById() 功能也是正常的,只是不建议,并且很少会这样做;

    2. void onStart()
    • Activity正在启动,此时Activity已经看见,但是没有展现在前台,没有获取到焦点,当然也就不能与用户交互,只有当执行到onResume方法的时候才可以进行交互。
    • 因为该方法是Activity重新回到前台时第一个回调的方法,因此在该方法里我们可以去检查某些必须的系统特性是否可用,比如网络是否在连接, GPS是否打开等类似的功能。
    • 该方法中我们通常初始化一些变量,当然这些变量必须是在Activity处于前台的时候才能够被响应。

    另外提一点,Google的文档里有写onStart方法可以直接到onStop方法不经过onResume和onPause,我想了一下就在onStart方法里调用了一下finish()方法,果不其然onStart后就直接onStop了,但是没有什么实际意义,只能算是一个脑机急转弯吧。

    3. void onResume()
    • Activity可见可交互。
    • 如果Activity是重新打开,此时就需要在该方法中重新实例化在onPause()中释放的资源。 初始化在前台显示时需要的资源,如:动画、播放视频。此外建议在onResume()中打开独占设备,比如相机。之所以在该方法中打开是因为当打开新的Activity时,首先会onPause掉旧Activity,然后在onCreate, onStart, onResume新Activity,如果之前旧Activity已经打开了独占设备(相机), 那此时onPause旧Activity时就可以释放掉独占设备(相机),那么打开的新Activity就能够使用独占设备(相机)了。
    4. void onPause()
    • Activity已经暂停,可见但不在前台,因此也不可交互。
    • 该方法中需要要将活动的状态持久化,比如持久化用户数据、停止动画,暂停正在播放的视频等不太耗时的操作。
    • 释放部分占用的系统资源(尤其是独占设备),如:相机, GPS等,设置有时会让该Activity断开网络连接,因为这些工作会大幅度占用系统资源,增加电耗或者流量消耗。
    • 因为打开新的Activity前回去回调旧Activity的onPause方法,因此onPause方法中不能做太耗时的操作(如,数据库读写,IO操作),否则调新的 Activity 在切换时可能会出现卡顿现象,这是用户不想看到的。 耗时的清理工作应该放在onStop方法中。
    5. void onStop()
    • Activity即将停止,此时当然不可见,即一个活动不再需要展示给用户的时候。
    • 耗时的清理工作在onStop方法中,一些较为重量级回收操作,比方说关于数据库的一些读写操作等。
    • Activity 在此状态时仍然存在于内存中,如果在系统内存不够时,系统接下来很快会销毁掉该Activity,在极端情况下,直接 kill Activity 且不执行onDestroy()函数。所以务必在onStop()函数中就清理掉可能引起内存泄露的资源,当然更极端的时系统内存已严重不足,导致系统无法保留该进程的情况下,onStop() 可能都不会被执行,所以保存状态信息是应该在onPause时做,而不是onStop时候做。
    • 活动如果没有在前台运行,都将被停止或者Linux管理进程为了给新的活动预留足够的存储空间而随时结束这些活动。因此对于开发者来说,在设计应用程序的时候,必须时刻牢记这一原则。在一些情况下,onPause方法或许是活动触发的最后的方法,因此开发者需要在这个时候保存需要保存的信息。
    6. void onDestroy()
    • Activity即将被销毁。
    • 和 onStop方法一样,如果内存紧张,系统会直接结束这个活动而不会触发该方法。
    • 很多情况下 Activity 是不需要定义这个函数,因为在onPause()和onStop()中,大多数的清理工作都已经完成了。但是,如果在onCreate()中定义了后台线程,或者可能引起内存泄露的代码,那就需要在onDestroy()中清理,如,静态对象持有其他Activity的引用,广播注销等操作。

      这里需要提到的一点是,即使一个Activity被销毁后app内部的static变量是不会被销毁的,因为static变量是全局的,activity销毁但是该app的进程并没有被杀死。所以说这一点尤为需要注意我们的static变量的使用,否则稍有不慎再次启动该activity的时候该static变量就会是一个dirty data!

    7. void onRestart()
    • Activity正在被重新启动。
    • 在原Activity没有销毁时重新要回到该Activity时会回调该方法,紧接着会回调onStart方法,一般在该方法中恢复用户数据。

其实Activity生命周期函数可以看成是成对的,onCreate和onDestory成对,onStart和onStop成对,onResume和onPause成对,这在上述每个回调函数的介绍中也可以看出来。

  • Activity启动、销毁常见的几种情况
    • 一个Activity的启动顺序:

      onCreate()——>onStart()——>onResume()

    • 当另一个Activity启动时:

      正常情况:第一个Activity onPause()——>第二个Activity onCreate()——>onStart()——>onResume() ——>第一个Activity onStop()

      特殊情况:第二个Activity因为尺寸小没有完全覆盖第一个Activity,或者第二个Activity是透明的, 此时第一个Activity的onStop方法是不会被执行的,即第一个Activity onPause()——>第二个Activity onCreate()——>onStart()——>onResume()

    • 当返回到第一个Activity时:

      第二个Activity onPause() ——> 第一个Activity onRestart()——>onStart()——>onResume() ——>第二个Activity onStop()——>onDestroy()

    • 一个Activity的销毁顺序:

      (情况一)onPause()——>

      (情况二)onPause()——>onStop()——>

      (情况三)onPause()——>onStop()——>onDestroy()

    注:因此应在onPause()和onResume()做保存或者暂停动作。 同时我们应该思考Google工程师为什么要这样设计生命周期的顺序。他们是基于什么样的考虑,这样便于我们更好的理解Activity的生命周期。

同时利用下图对照四种状态来理解生命周期:

Android笔记 Activity详解_第2张图片


  • 横竖屏切换时Activity的生命周期

    这个生命周期跟清单文件里的配置有关系 (注意:横屏、竖屏切换时候生命周期也不一样)

    • 不设置Activity的Android:configChanges时,切屏会重新调用各个生命周期 默认首先销毁当前activity,然后重新加载

      1. 切换到横屏
            onSaveInstanceState
            onPause
            onStop
            onDestroy
            onCreate
            onStart
            onRestoreInstanceState
            onResume
            
        2. 切换到竖屏,销毁了两次
            onSaveInstanceState
            onPause
            onStop
            onDestroyonCreate
            onStart
            onRestoreInstanceState
            onResume
            onSaveInstanceState
            onPause
            onStop
            onDestroy
            onCreate
            onStart
            onRestoreInstanceState
            onResume
    • 设置Activity的android:configChanges="orientation|keyboardHidden|screenSize"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

      3. 修改AndroidManifest.xml,把该Activity添加 android:configChanges="orientation",切横屏,只销毁一次。
      
            onSaveInstanceState
            onPause
            onStop
            onDestroy
            onCreate
            onStart
            onRestoreInstanceState
            onResume
      
        4. 再切回竖屏,发现不会再打印相同信息,但多打印了一行onConfigChanged
      
            onSaveInstanceState
            onPause
            onStop
            onDestroy
            onCreate
            onStart
            onRestoreInstanceState
            onResume
            onConfigurationChanged
      
      
        5. 更改android:configChanges="orientation"改成android:configChanges="orientation|keyboardHidden"
        切横屏,就只打印onConfigChanged
      
            onConfigurationChanged
      
      
        6. 切回竖屏
      
            onConfigurationChanged
            onConfigurationChanged

总结:

1. 不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
    
2. 设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
    
3. 设置Activity的Android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行
onConfigurationChanged方法。(执行这个方法,必须设置sdk version 大于等于13.0)
    
附:设置android:screenOrientation="portrait"则无论手机如何变动,拥有这个属性的activity都将是竖屏显示。
    同样的,android:screenOrientation="landscape",为横屏显示。



以上是Activity的正常生命周期,下面是Activity的异常生命周期:

1. 资源相关的系统配置发生改变导致Activity被杀死并重新创建

比如说当前Activity处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了改变,在默认情况下,Activity就会被销毁并重建,也可以阻止系统重新创建Activity,生命周期如下:

Android笔记 Activity详解_第3张图片

当系统配置发生改变,Activity会被销毁,其onPause、onStop、onDestory均会被调用。但是因为在异常情况下终止的,所以系统会调用onSaveInstanceState来保存当前Activity状态。这个方法是在onStop之前,与onPause没有固定的时序关系。当Activity重建的时候系统会把onSaveInstanceState所保存的Bundle作为对象传递给onRestoreInstanceState和onCreate方法。

  • Activity的onSaveInstanceState和onRestoreInstanceState

    1. 出现异常情况。
    2. Activity被销毁,回调onPause -> onStop -> onDestroy。
    3. 因为Activity是在异常情况下终止的,系统会调用onSaveInstanceState来保存当前Activity的状态。此方法在onStop之前调用。它与onPause没有既定的时序关系。
    4. Activity被重新创建,回调onCreate -> onStart -> onResume; 系统会将上次异常终止时保存的状态传递onRestoreInstanceState和onCreate。onRestoreInstanceState会在onStart之后被调用。
  • View的onSaveInstanceState和onRestoreInstanceState

    1. 出现异常情况。
    2. Activity被销毁,系统会默认保存当前Activity的视图结构:
    1. Activity调动onSaveInstanceState去保存数据;
    2. 然后Activity会委托Window去保存数据;
    3. Window再委托它的顶级ViewGroup去保存数据;
    4. 其顶级ViewGroup再一一调用它的子视图View的onSaveInstanceState来保存数据。
    1. Activity被重新创建,系统会恢复上次异常终止时保存的视图结构,其onRestoreInstanceState流程与上面类似,也是上层委托下层。
  • 总结:

    • View的源码中每个View都有onSaveInstanceState和onRestoreInstanceState这两个方法。
    • 接收位置可以是onRestoreInstanceState和onCreate方法,区别是:onRestoreInstanceState如果被调用,参数Bundle一定是有值的,在onCreate中需要判断参数是否为null。
    • onSaveInstanceState只有在Activity即将销毁并有机会重新显示时才会调用(切记是有机会重新显示才会调用否则就不调用),比如:旋转屏幕,按Home键等,正常销毁的Activity生命周期中不会调用。
    • 在onSaveInstanceState和onRestoreInstanceState方法中,系统默认做了一定的恢复工作,默认保存Activity的试图结构,并在Acitivity重启后恢复这些数据,比如文本框中的数据,ListView滚动的位置等。
2. 资源内存不足导致低优先级的Activity被杀死

Activity按照优先级从高到低,可分为如下三种:

  • 前台Activity——正在和用户交互的Activity,优先级最高
  • 可见但非前台Activity——比如Activity中弹出了一个对话框,导致Activity可见但是位于后台无法与用户直接交互。
  • 后台Activity——已经被暂停的Activity,比如执行了onStop,优先级最低。 当系统内存不足时,系统就会按照上述优先级去杀死目标Activity所在的进程,并在后续通过onSaveInstanceState和onRestoreInstanceState来存储和恢复数据。如果一个进程中没有四大组件在执行,这个进程很容易被杀死,较好的方法是将后台工作放入Service中保证有一定的优先级,不容易被系统杀死。

如果当某项内容发生改变后,不想Activity重新创建,就可以给Activity指定configChanges属性,多个值用“|”连接起来。

android:configChanges="orientation | keyboardHidden"

Android笔记 Activity详解_第4张图片


参考:

http://blog.csdn.net/u010784887/article/details/51669699

http://www.jianshu.com/p/a30cec0f426b

http://blog.csdn.net/liuhe688/article/details/6733407


本文仅是作为学习笔记API,参考查阅,如有错误,欢迎指正,谢谢!


你可能感兴趣的:(Android笔记-基础,Android笔记)