[Android编程心得]Activity的生命周期函数

在使用Eclipse添加一个新的Activity时,系统会自动生成OnCreate()函数,而其他生命周期函数,例如OnStart() OnReSume()等它是不负责自动生成的,也因为这样,就会被很多开发者忽略,从而产生一些意想不到的错误。

在之前翻译的文章中,分别讲过各个生命周期函数的用法,这里整理一下。

下面是之前翻译的官方文档,里面包含了更详细的实例。

[Andriod官方训练教程]管理Activity的生命活动之开始一个Activity

[Andriod官方训练教程]管理Activity的生命活动之暂停和恢复一个Activity

[Andriod官方训练教程]管理Activity的生命活动之停止和重启一个Activity

[Andriod官方训练教程]管理Activity的生命活动之重新创建一个Activity


综述

一个Activity的生命周期图如下所示:


总体来说,一个Activity只有3种静止状态(其他状态都是瞬时的):

  1. Resumed 重新开始:在该状态下,activity是处于前台的,并且用户可以与它进行交互。(有时同样表示为"running"状态)    
  2. Paused 暂停:在该状态下,activity部分的被另一个activity所掩盖——另一个在前台的activity是半透明的或者没有占据整个屏幕。暂停的activity不再接受用户输入并且不可以执行任何代码。
  3. Stopped 停止: 在该状态下,activity被完全隐藏并且对于用户是不可见的;它被认为是处于后台。当停止时,该activity实例和它的所有状态信息,例如成员变量将被保留,但是它不可以执行任何代码。
首先谈谈暂停(Paused)和停止(Stopped)状态。这两个都是静止状态,即应用程序可能长时间处于的状态。它们的不同主要有以下几个方面:
  • 在通常的app使用中,前台的activity(Resumed状态)有时会被另一个可见的部件阻塞从而引起该activity发生暂停。例如,当某个应用程序请求打开蓝牙时会出现一个打开蓝牙的对话框,那么之前的activity就暂停了(Paused状态)。当你的activty进入暂停阶段(Paused状态)时,系统在你的Activity中调用onPause()方法,你可以重载这个方法来停止一些正在进行的动作,而这些动作不应该在暂停时继续进行(例如一个视频),或是在用户离开你的app时保留任何应该永久保存的信息。注意,当你的activity接收到一个onPause()调用时,它可能预示着activity将要被暂停一段时间,并且用户可能会返回你的activity。但是,这最可能表示用户正在离开你的activity。.当一个半透明的activity(例如之前提到的蓝牙开启对话框等)阻塞你的activity时,系统调用onPause(),然后activity将在Paused状态等候。之后用户再次返回到activity(例如在蓝牙开启对话框出现后,选择了“是”或“否”,该对话框就会自动消失)时,系统将调用onResume()
  • 一旦activity被完全阻塞并且不再可见,它将会停止(Stopped状态)。
了解系统何时停止(Stop)和重启(ReStart)你的activity也是很重要的,这确保你的用户可以感到你的app总是活跃的而不是丢失了他们的进程。在以下几种情况下你的activity需要被停止或是重启(请注意上图中需要调用的各种方法):
  • 用户打开了“最近使用的应用程序”窗口,然后从你的app切换到另一个app。那么你的app里正在前台运行的activity就停止了。如果用户从主菜单里的开启图标或者“最近使用的应用程序”窗口返回到你的app,那activity就会重启。
  • 用户在你的app里执行了一个开始新的activity的动作。那么当前的activity在第二个activity创建时就停止了。如果用户后来就按下了返回按钮,那么第一个activity就会重启。这里有个问题需要注意,返回按钮指的是手机下方自带的返回按钮,而不是创建一个activity的布局文件时自动创建的Up按钮。
    首先我们来弄清楚两个按钮(Up和Back)的区别。
    Android <wbr>4 <wbr>导航(Navigation) <wbr>- <wbr>part <wbr>1
    如图所示,当点击左方的按钮时,系统会将当前的activity弹出栈(一般来说,当一个应用启动时,会同时启动一个Task,然后在这个task里面按照堆栈的方式按照启动的顺序放入activity。举例来说,一个应用包含了A, B, C, D四个Activity. 用户点击activity的顺序是A, B, C, B, D, 那么在task里面,从栈第到栈顶依次会是A, B, C, B, D这5个activity的实例。 这个时候,在D界面上点击back(这里的back是指手机下方的返回按钮),D就会被弹出堆栈,android会显示activity B, 并且堆栈变为A, B, C, B),并且调用该activity的OnDestroy()方法,而之前的activity就会重启(只调用OnReStart()函数,而不会调用OnCreate()函数,之前它是处于暂停状态的,savedInstanceState也不为空,并保存了之前的一些信息)。
    但是,当点击右图时,系统会显示当前activity的父activity,它的父activity将会被重新创建,注意这里不是重新启动,它会调用OnCreate()方法来创建一个全新的实例,你也不可以使用savedInstanceState来企图初始化数据,因为此时这个实例是第一次被创建。如果在OnCreate()方法里你调用了类似于getIntent()这样的方法来得到它的父activity传来的数据,就有可能出现错误。这是因为,系统默认当点击Up按钮时,调用的方法是:
    @Override
    	public boolean onOptionsItemSelected(MenuItem item) {
    		switch (item.getItemId()) {
    		case android.R.id.home:
    			NavUtils.navigateUpFromSameTask(this);
    			return true;
    		}
    		return super.onOptionsItemSelected(item);
    	}
    解决方法是将NavUtils.navigateUpFromSameTask(this)方法改为finish(),即:
    @Override
    	public boolean onOptionsItemSelected(MenuItem item) {
    		switch (item.getItemId()) {
    		case android.R.id.home:
    			finish();
    			return true;
    		}
    		return super.onOptionsItemSelected(item);
    	}
    
    这样,当按下Up按钮后,当前的activity会自动销毁,从而就会显示上一个activity,起到up的作用,但又避免了重现创建一个新的父activity。
  • 用户在使用你的app时接到了一个电话。
Activity类提供了两个生命周期方法,onStop() onRestart(),它们允许你明确地控制你的activity该如何停止和重启。和暂停状态(只是局部的UI被阻塞)不同,停止状态确保UI对用户不再可见,而且用户的焦点在单独的一个activity上(或是完全是另一个单独的app)。因为当你的Activity实例停止时系统在内存中仍然保留了它,你可能不需要实现onStop() onRestart()(甚至是onStart()方法。对于大多数相对简单的activity,它们可以好好地停止和重启,而你可能只需要使用onPause()来暂停正在进行中的动作并且和系统资源分离)。当用户离开你的activity时,系统调用onStop()来停止activity (1)。如果当activity停止时用户再次返回,系统调用onRestart(),紧接着调用onStart()onResume()。你应该注意到无论哪种情况下使得activity停止,系统都将先调用onPause()再调用onStop()

下面我们需要了解一下何时activity会被销毁(Destroy)和重建(Create):
  • 有一些情况下你的activity因为正常的app行为而被销毁,例如当用户按下返回按钮或者你的activity调用了finish()预示着它本身的销毁。当你的activity因为用户按下返回按钮而自己销毁时,系统中的Activity实例会永久消失,因为这样的行为表明activity不再被需要了。
  • 如果你的activity当前是停止状态(请见前面描述何时会进入停止状态)并且在很长时间内没有被使用,或者前台的activity需要更多的资源因此系统需要关闭后台程序来回收内存,系统都有可能会销毁你的activity。这样的因为系统约束(而不是正常的app行为)而销毁activity的情况下,尽管真正的Activity实例已经消失,系统仍然记得它的存在,这样当用户导航回到它时,系统将使用保存的数据(表述了activity销毁时的状态)来创建一个新的activity实例。系统用于重新载入之前状态的保存的数据被叫做“实例状态”,它是一个存储在一个Bundle对象中的键-值对集合。
  • 每次用户旋转屏幕时,你的activity将会被销毁然后再重建。当屏幕改变方向时,系统销毁并重建前台的activity,因为屏幕的设置发生了变化而你的activity可能需要加载另一些资料(例如布局)。默认下,系统使用Bundle实例状态来保存你的activity布局(例如输入到EditText对象中的文本值)中的每个View的相关信息。因此,如果你的activity实例被销毁再被重建后,布局的状态会被重新载入为它之前的状态而不需要你编写任何代码。但是,你的activity可能需要你想要载入的更多的信息,例如activity中追踪用户进程的成员变量。注意,为了Android系统重载你的activity中views的状态,每一个view都必须有一个唯一的ID,以android:id属性提供。为了保存额外的有关activity状态的数据,你必须重载onSaveInstanceState()回调方法。当用户准备离开你的activity时系统将调用这个方法,并将它传递给Bundle对象以便你的activity意外销毁时可以被保存。
下面再仔细描述一下各个方法使用时的注意事项。


onCreate(Bundle savedInstanceState)函数

在 onCreate() 方法里,我们可以执行基本的应用程序启动逻辑(这些逻辑只在activity的整个生命活动中发生一次)。例如,你的onCreate() 的实现应该定义了用户界面并且可能实例化一下类的变量。我们可以注意到,这个方法中包含了一个savedInstanceState变量。若该activity不是第一次被创建,并且系统记得它的存在,那么该变量里就会保存一些必要的信息,正如上面讲到的那样。你也可以通过重载onSaveInstanceState()方法来保存自己的信息。这样在下一次重建调用OnCreate方法时,就可以恢复该信息。
该方法在activity第一次创建或重建时会调用。


onDestroy()函数


activity的第一个生命周期回调函数是onCreate(),而它的最后一个回调函数是onDestroy()。系统调用该方法作为一个最终信号,你的activity实例将要被完全从系统内存中清除。大多数apps不需要实现这个方法,因为随着你的activity,局部的类引用类型将随之销毁,并且你的activity在 onPause() and onStop()期间完成了大部分清理工作。但是,如果你的activity包含了后台线程(在onCreate()中创建)或者其他长期执行的资源,如果没有合适地关闭就有可能造成内存泄露,你应该在onDestroy()中结束它们。
除了一种情况外,系统在所有情况下,都是在已经调用了onPause() 和onStop()后再调用onDestroy()。这种情况是:当你在onCreate()中调用finish()方法。在一些情况下,例如当你的activity运行为一个暂时的决策人来启动另一个activity,你可能在onCreate()中调用finish()来销毁该activity。在这种情况下,系统立刻调onDestroy(),不再调用其他任何生命周期函数。
当系统销毁你的activity时,它将为你的Activity调用onDestroy()方法。因为你通常应该在onStop()里释放几乎所有的资源,等到你收到一个onDestroy()的调用时,大多数app不需要做太多的事情。这个方法是你清除那些会造成内存泄露的资源的最后的机会,因此你应该确保附加的线程被全部销毁,其他长期运行的动作,像追踪函数等,也同样被停止了。
请见上面描述何时会销毁一个activity。

onPause()函数


当系统调用onPause()时,在技术上意味着你的activity仍是部分可见的,而其他情况下这意味着用户正在离开activity,并且将到达Stopped状态。通常情况下,你应该用onPause()回调函数来:

  • 停止动画或其他正在进行的会消耗CPU的动作。
  • 提交为保存的变化,但是只在当他们离开并且期望这些变化被永久保存时(例如邮件草稿)。
  • 释放用户不需要的系统资源,例如广播收音机,传感器手柄(像GPS),摄像头,或是任何可能影响电池寿命的资源。

通常,你不应该使用onPause()来将用户变化(例如键入表单的个人信息)永久存储。只有当你确定用户希望这些变化自动存储时(例如草稿邮件),你才应该在onPause()中永久保存这些变化。但是,你应该避免在onPause()中进行密集的CPU工作,例如向数据库写入数据,因为这会减慢向下一个activity的可视转换(相反的,你应该在onStop()中进行这些高负荷的关闭动作)。你应该保持onPause()中完成的操作的数目相对简单,以便当你的activity真的需要停止时,可以允许快速地向用户的下一个目标转换。

当你的activity暂停时,该Activity实例被驻留在内存中,并且在activity继续时被重新调用。你不需要重新初始化那些已经在任何回调函数中创建的部件。


onResume()函数


记住,每次你的activity进入前台时,系统都会调用这个方法,包括当第一次创建它时。同样的,你应该实现onResume()来初始化你在onPause()释放的部件,并且执行那些在进入Resumed状态时必须出现的初始化动作(例如开始动画,初始化那些当activity获得用户聚焦时需要的部件)。


onStop()函数

当你的activity收到一个onStop()方法的调用时,它将不再可见并且应该释放几乎所有用户在不使用它的所不需要的资源。一旦你的activity停止,如果系统需要回收系统内存,它就可能会销毁这个实例。在极端情况下,系统可能会杀死你的app进程而不需要调用activity的终极onDestroy()回调函数,因为使用onStop()来释放那些可能造成内存泄露的资源是很重要的。尽管onPause()方法在onStop()之前被调用,你应该使用onStop()来进行更大量的、更密集的CPU操作,例如向数据库写入信息。
当你的activity停止时,Activity对象被保留在内存中,然后在activity重新开始时被再次调用。你不需要再次初始化那些在任何回调函数中创建的部件。系统还将跟踪布局中每个View的当前状态,因此如果用户在EditText窗口中输入文字,那这些内容会被保留因此你不需要保存和重新载入它们。
注意:即使在你的activity停止时系统销毁了它,系统仍然在一个Bundle(一个键-值对的二进制大对象,也就是前面在OnCreate()函数中的参数savedInstanceState)中保留了View对象的状态(例如一个EditText中的文本),如果用户导航到同样的activity实例系统将重新载入它们。

onStart()函数


当你的activity从停止状态返回到前台时,它收到一个onRestart()的调用。系统还会调用onStart()方法,这个方法在你的activity变得可见时都会发生(不管是被重启还是第一次被创建)。但是,onRestart()方法仅在activity从停止状态重新开始时才会被调用,因此你需要使用它来执行特殊的恢复工作(仅在activity之前停止了但未被销毁的情况下的必要的工作)。
个app需要使用onRestart()来重新载入activity的状态是不常见的,因此对于这个应用于母体app的方法没有任何指导。但是,因为你的onStop()方法本质上应该清除你的activity的所有资源,在activity重启时你将需要重新实例化它们。然而,在你的activity第一次创建(这时没有任何存在的activity实例)时,你还需要实例化它们。出于这个原因,你通常应该使用onStart()回调函数作为onStop()方法的对应版本,因为系统在创建你的activity和停止时重启activity都会调用onStart()
例如,因为用户在返回时可能已经离开你的app很长一段时间了,onStart()方法是一个核实系统性能是可用的的一个绝佳的地方:

最后,讲一下与活动状态的保存与重载有关的两个函数:onSaveInstanceState()onRestoreInstanceState()

当系统开始停止你的activity时,它调用onSaveInstanceState() ,因此万一Activity实例必须被重建时你可以指明你想抱保存的额外状态。如果activity被销毁并且一个相同的实例必须被重建,系统将(1)中定义的状态传递给onCreate() 方法 (2) 以及onRestoreInstanceState()方法 (3)。有一些情况下你的activity因为正常的app行为而被销毁,例如当用户按下返回按钮或者你的activity调用了finish()预示着它本身的销毁。当你的activity因为用户按下返回按钮而自己销毁时,系统中的Activity实例会永久消失,因为这样的行为表明activity不再被需要了。

onSaveInstanceState(Bundle savedInstanceState)方法


当你的activity要停止时,系统调用onSaveInstanceState(),因此你的activity可以用一个键-值对集合保存状态信息。这个方法的默认实现保存了activity中view的层级结构信息,例如EditText中的文本或是ListView中的滚动位置。
为了保存你的activity中额外的信息,你必须实现onSaveInstanceState(),然后向Bundle对象中添加键-值对。警告:永远调用onSaveInstanceState()的父类实现,因为默认实现可以保存view层级结构的状态。

onRestoreInstanceState(Bundle savedInstanceState)方法


当你的activity之前被销毁再被重建时,你可以从Bundle中恢复你保存的状态。onCreate() 和onRestoreInstanceState()回调函数都接收包含了相同的状态信息的Bundle对象。因为onCreate()方法在创建一个新的实例以及重建一个先前的实例都会被调用,在你试图读一个Bundle之前你必须检查它的状态是否是null。如果它是null,那么系统将会创建一个新的activity实例,而不是重新载入之前被销毁的一个。你可以在onCreate()中重载相同的状态数据。
你也可能选择去实现onRestoreInstanceState()(系统在onStart()方法后调用)而不是在onCreate()重新载入状态。系统仅在有某个保存的状态需要被重载时才调用onRestoreInstanceState()
警告:永远先调用onRestoreInstanceState()的父类实现,因为默认实现可以重新载入view层级结构的状态。
原文地址:https://www.cnblogs.com/xiaowangba/p/6314733.html