代码改变世界

Activity相关知识点总结

2013-12-19 01:54  soar.  阅读(1889)  评论(3编辑  收藏  举报

一、Activity状态

  Activity有三种状态:active/running、paused、stopped。

  1、active/running状态,在当前屏幕时,即用户可见的Activity,位于当前Task的栈顶。

  2、paused状态,Activity失去焦点但对用户依然可见。也就是说在它上面有另外一个非全屏或者透明的Activity,并成为了当前的焦点。它还没有被其他的Activity完全遮盖住,而paused的Activity依然是alive状态的,它保留着所有的状态和成员信息并连接至窗口管理器,但当系统处于极低内存的情况下,仍然可以杀死这个Activity。

  3、stopped 状态,当Activity完全被另一个Activity覆盖时,它仍然保留所有的状态和成员信息。但它不再被用户可见,所以它的窗口将被隐藏,当其它地方需要内存,则系统经常会杀死这个Activity。

  当Activity是paused或者stopped状态时,系统可以通过要求它结束(调用它的finish()方法)或直接杀死它的进程来将它驱出内存。当它再次为用户可见的时候,它只能完全重新启动并恢复至以前的状态。

启动并恢复至以前的状态。

二、为什么会有这么麻烦的状态变化

  1、手机屏幕大小有限,只能看到有限的界面数量,用户需要通过Back键或Home键或其他方式切换Activity。

  2、在有手机来电时,系统会优先切换显示电话接听界面。

  由于上述的一些原因,确实存在界面随时可能发生切换的情况,最佳方式当然不是每次都直接销毁之前的界面,很多时候我们也需要在回到之前界面后恢复之前的状态。我们需要了解这些状态,当然还包括要掌握Activity的“生命周期”等知识,这样就能够在Activity发生变化时,知其所以然,并能够根据需求采取一定的措施,例如切换界面时,保存当前的界面信息,即使其被意外杀死也能恢复之前状态。

三、Activity生命周期

Activity生命周期

  当一个Activity从这个状态转变到另一个状态时,它被以下列protected方法所通知:

public class Activity extends ApplicationContext 
{  
         protected void onCreate(Bundle savedInstanceState);
    
         protected void onStart();
    
         protected void onRestart(); 
    
         protected void onResume();
    
        protected void onPause();  
    
        protected void onStop();  
    
        protected void onDestroy();  
}

  1、onCreate -- 当Activity第一次创建时会被调用(未被销毁前不会被再次调用)。在这个方法中可以做一些初始化工作,例如对创建新的View、获取并设置View的一些属性、绑定列表的数据等等。如果能捕获到Activity 状态的话,这个方法传递进来的Bundle对象将存放了Activity当前的状态。调用该方法后一般会调用onStart()方法。此时Activity不可见,所以并不是所有的初始化工作都适合在这里做,例如一些动画的开始。

  2、onRestart -- 在Activity被停止后重新启动时会调用该方法。其后续会调用onStart方法。

  3、onStart -- 当Activity对于用户可见前即调用这个方法。如果Activity回到前台则接着调用onResume() ,如果Activity隐藏则调用onStop()。此时Activity可能可见,但即使可见,也无法进行交互操作。

  4、onResume -- 在Activity开始与用户交互前调用该方法。在这时该Activity 处于Activity 栈的顶部,并且接受用户的输入。其后续会调用 onPause() 方法。此时Activity也不一定可见,需要通过onWindowFocusChanged(boolean)来确定Activity是否可见。

  5、onPause -- 在系统开始准备恢复其它Activity时会调用该方法。这个方法中通常用来提交一些还没保存的更改到持久数据中,停止一些动画或其它一些耗CPU的操作等等。无论在该方法里面进行任何操作,都需要较快速完成,因为如果它不返回的话,下一个Activity 将无法恢复出来。如果Activity 返回到前台将会调用onResume(),如果Activity变得对用户不可见了将会调用onStop() 。

  6、onStop -- 在Activity对用户不可见时将调用该方法。可能会因为当前Activity 正在被销毁,或另一个Activity(已经存在的Activity 或新的Activity )已经恢复了正准备覆盖它,而调用该方法。如果Activity 正准备返回与用户交互时后续会调用onRestart ,如果Activity正在被释放则会调用onDestroy 。

  7、onDestroy -- 在Activity被销毁前会调用该方法。这是Activity能接收到的最后一个调用。可能会因为有人调用了finish方法使得当前Activity正在关闭,或系统为了保护内存临时释放这个Activity的实例,而调用该方法。你可以用isFinishing方法来区分这两种不同的情况。

  要注意的是,onPause(),onStop(),onDestory()这3个方法都可能会因为系统内存不足而被系统直接kill。而平常从一个Activity转向/回到另一个Activity时,当新Activity是full screen(弹出窗口,例如AlertDialog是不算的)的时候就会调用前一个Activity的onPause(),然后调用onStop(),而无论onPause或者onStop,都有可能被kill,所以一般在onPause时就应该保存需要持久化的一些数据(例如用户编辑的信息)。

  onCreate、onStart、onResume都不是Activity准确能够交互的点,真正的是onWindowFocusChaned()函数被执行时。

四、Android的进程

  android根据其重要性在内存不足的时候移去重要性最低的进程。重要性由高到低为:

  1、活动/前台进程

    指那些有组件正和用户进行交互的应用程序进程。他们都是android尝试通过回收资源来使其保持响应的进程。这些进程的数量非常少,只用到最后的关头才会终止这些进

程。

    活动进程包括:

      处于“活动”状态的Activity,也就是说,它们位于前台并对用户事件进行响应。
      正在执行onReceive事件处理程序的广播接收器。
      正在执行onCreate()、onStart()或onDestory事件处理程序的服务。
      正在运行,且已被标记为前台运行的服务。
  2、可见进程
    可见,但是非活动的进程是指那些驻留可见活动的进程。顾名思义,可见的活动能被用户看到,但是他们并不是在前台运行或者能对用户事件做出响应,比如,当一个活动Activity被部分遮挡的时候(被一个非全屏或者半透明状态的Activity遮挡时)就会出现这类情况。这类进程的数量很少,只有在资源极度缺乏的环境下,为保证活动进程的继续执行,才会终止这些进程。

  3、服务进程

    已经启动的服务进程。服务支持在没有可见界面的情况下,仍然能继续不间断地进行处理。因为后台服务没有直接和用户进行交互,所以它们的优先级要比可见进程低一些。但是他们仍然被认为是前台进程。除非活动或者可见进程需要资源,否则不会终止它们。

  4、后台进程
        不可见,并且没有任何正在运行的服务的活动的进程,通常会有大量的后台进程。这样的程序拥有一个用户不可见的Activity。这样的程序在系统内存不足时,按照LRU的顺序被结束。

    运行着一个对用户不可见的Activity(调用过onStop() 方法)。这些进程对用户体验没有直接的影响,可以在服务进程、可见进程、前台进程需要内存的时候回收。通常,系统中会有很多不可见进程在运行,他们被保存在LRU (least recently used) 列表中,以便内存不足的时候被第一时间回收。如果一个Activity正确的执行了它的生命周期,关闭这个进程对于用户体验没有太大的影响。
  5、空进程
    这样的进程不包含任何活动的程序部件。系统可能随时关闭这类进程。未运行任何程序组件。运行这些进程的唯一原因是作为一个缓存,缩短下次程序需要重新使用的启动时间。系统经常中止这些进程,这样可以调节程序缓存和系统缓存的平衡。

  Android对进程的重要性评级的时候,选取它最高的级别。另外,当被另外的一个进程依赖的时候,某个进程的级别可能会增高。一个为其他进程服务的进程永远不会比被服务的进程重要级低。因为服务进程比后台Activity进程重要级高,因此一个要进行耗时工作的Activity最好启动一个Service来做这个工作,而不是开启一个子进程――特别是这个操作需要的时间比Activity存在的时间还要长的时候。例如,在后台播放音乐,向网上上传摄像头拍到的图片,使用Service可以使进程最少获取到“服务进程”级别的重要级,而不用考虑Activity目前是什么状态。broadcast receivers做费时的工作的时候,也应该启用一个服务而不是开一个线程。

 

五、Activity状态的保存

protected void onSaveInstanceState (Bundle outState)
protected void onRestoreInstanceState (Bundle savedInstanceState)

  onSaveInstanceState() 和 onRestoreInstanceState() 并不是生命周期方法。它们并不是总会被调用。例如通过Back造成的销毁Activity时,它就不会被调用。应该只用它来为Activity保存一些临时的状态,而不能用来保存持久性的数据。而是应该用onPause()来达到这个目的。

  onPause()方法是在系统结束应用程序前调用的最后一个安全的方法。无法保证onStop和onDestroy会被调用,所以不能依赖这两个方法来实现关键逻辑。

六、Activity的加载模式

  Activity加载模式(通过在AndroidManifest.xml文件中activity元素的android:launcherMode属性设置) 。请参考文章结尾附带的demo体验Activity的加载模式。

  1、standard(默认)
    测试方式:MainActivity(standard),SecondActivity(standard)
    每次都是创建了新的Activity实例。

  2、singleTop
    测试方式:MainActivity(singTop),MainActivity自己intent自己
    测试方式:MainActivity(singleTop),SecondActivity(standard)
    和standard一样是发送新的实例,但singleTop要求如果创建intent的时候栈顶已经有要创建的Activity实例,则将intent发送给该实例。例如给MainActivity设置singleTop,然后按钮也是intent自己,那么会发现一直都是MainActivity当前这个实例,因为他一直在栈顶,所以不会创建新的。

    如果用A打开B,而B再打开A,如此循环,如果A是设置了singleTop,B是默认,则每次A都是新的,因为每次要打开A时,栈顶都不是A,就要创建新的A实例(和都是 standard没啥区别了)。
    此种模式的应用场景,目前想到就是为了解决自己在栈顶时,自己给自己发送intent可以不创建新的实例。实际中应用的也较少。

  3、singleTask
    测试方式:MainActivity(singleTask),SecondActivity(standard)
    只创建一个实例。如果发现有对应的Activity实例,则是此Activity实例之上的其他Activity实例全部出栈,使此Activity实例成为栈顶对象,显示出来。
  4、singleInstance
    这个模式下的Activity单独在一个task栈中。这个栈只有一个Activity。目的是为了多个Task共享一个Activity。

七、Activity与View的生命周期

  View和Activity一样也有自己的生命周期,具体在View的周期中包含哪些通知函数,参见http://developer.android.com/reference/android/view/View.html。其中onMeasure、onLayout、onDraw最重要,而onMeasure最难理解(之后会单独讨论这个函数及其如何使用)。

八、Activity的注意事项

  1、onConfigurationChanged

    1)不设置Activity的android:configChanges时,屏幕切屏会导致当前Activity被销毁并重新创建。

    2)设置Activity的android:configChanges=“orientation”时,在3.2以前的版本会阻止系统默认的行为,即销毁并重新创建当前Activity。而3.2+的需要另外加上screenSize。
    3)而实际运行中还会有很多系统的配置改变导致Activity被销毁并重新创建,例如键盘模式、全局字体大小发生改变等等(具体有哪些参见http://developer.android.com/guide/topics/manifest/activity-element.html),对于这些配置的改变,不应该盲目使用configChanges配置拦截,理应根据实际需求来决定是否拦截及处理。

    4)当使用onConfigurationChanged自行处理时,必须调用super.onConfigurationChanged(newConfig),不能删除,否则会报调用异常错误。

九、参考文章

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

  http://marshal.easymorse.com/archives/2950

  android:configChanges  

  http://blog.csdn.net/imdxt1986/article/details/7339711

  http://blog.csdn.net/huiguixian/article/details/8071821

  http://bbs.csdn.net/topics/390413976

 

 

Activity加载模式测试DEMO