博客逐步迁移至 极客兔兔的小站html
接下来将介绍 Android Activity(四大组件之一) 的生命周期, 包含运行、暂停和中止三种状态,onCreate、onStart、onResume、onPause、onStop、onDestroy六种系统调用方法。java
如图所示,Activity实例能够在生命周期状态发生关键性转换时完成某些工做。android
- onCreate()
建立
,该方法是最常被覆盖的方法,第一次建立实例时调用, 通常用来完成实例建立的初始化操做,包括实例化组件,设置监听器,访问外部模型数据等。- onStart()
开始
,当Activity处于可见状态的时候就会调用onStart方法,包括建立完实例显示,或者从其余活动切换到活动时调用。- onResume()
准备
,当Activity得到用户焦点时调用。- onPause
暂停
,当Activity准备调用或者恢复另外一个活动时调用,失去焦点时,例如启动一个Dialog调用。该方法能够释放一些消耗CPU的资源,保存一些关键数据,可是执行速度要快,不然影响新的栈顶活动使用。- onStop
中止
,彻底不可见时调用。例如成功启动了另一个活动,该活动离开栈顶不可见。启动Dialog不会执行该方法。- onDestroy
销毁
,这个方法在活动销毁时调用。
// 可使用如下方法进行测试。 public class MainActivity extends Activity { private String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG,"Create"); } @Override protected void onStart() { super.onStart(); Log.d(TAG, "Start"); } @Override protected void onResume() { super.onResume(); Log.d(TAG, "Resume"); } @Override protected void onPause() { super.onPause(); Log.d(TAG, "Pause"); } @Override protected void onStop() { super.onStop(); Log.d(TAG, "Stop"); } @Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, "Destroy"); } }
使用上面的日志打印测试方法发现, 设备旋转时生命周期如图所示,即设备旋转时,当前活动实例会被系统销毁,而后建立一个新的实例。ide
由于旋转设备会改变设备配置(device configuration),设备配置包括屏幕的方向、密度、尺寸、键盘类型、底座模式等,为匹配不一样的设备,可使用不一样的布局文件,这和Web开发中 针对不一样宽度的屏幕选择不一样CSS样式殊途同归,如何建立不一样布局适配不一样配置设备不在本文讨论之列。布局
设备旋转时,临时数据会丢失。例如你使用了一个变量记录了用户点击了多少次按钮,设备旋转以后,Activity从新建立,这个变量就被初始化了,这里可使用Bundle
对象来恢复。保存数据能够覆盖onSaveInstanceState()
方法。测试
例以下面的代码,按3次按钮,旋转屏幕后,将打印出saved currentPage:3 init mCurrentPage:0,点击次数存在了Bundle对象中,并在onCreate()中获取到。3d
/* * onSaveInstanceState()一般在onPause、onStop、onDestroy前由系统调用 * onCreate()传入的参数savedInstanceState可获取保存的变量 */ public class MainActivity extends Activity { private static final String KEY = "currentPage"; private static final String TAG = "MainActivity"; private Integer mCurrentPage = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mCurrentPage += 1; } }); if(savedInstanceState != null){ // 打印使用Bundle保存的currentPage信息 Log.d(TAG,"saved currentPage: " + savedInstanceState.getInt(KEY,0)); // 打印新建活动mCurrentPage的值,总为0 Log.d(TAG,"init mCurrentPage: " + mCurrentPage); // ... update code } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // 使用key-value对的方式存储临时变量 outState.putInt(KEY, mCurrentPage); } }
当系统回收内存时,处于Pause、Stop状态的Activity可能被销毁,此时系统会调用onSaveInstanceState(),用户数据被存储在Bundle对象中,系统将Bundle对象放入Activity记录,能够将这种状态理解为Activity的暂存状态(无实例有记录)。日志
Activity暂存后,当前活动不复存在,Activity记录可帮助用户返回应用时活动的快速恢复,提供一个好的用户体验。可是当用户按了后退键,系统会完全销毁当前活动,Activity记录同时被清除,系统重启也会被清除该记录。code
standard是活动默认的启动模式,Android是使用返回栈来管理活动的,所谓栈就是先进后出,后进先出。该模式下,每启动一个新的活动,就会在返回栈中入栈,并处于栈顶的位置(即用户当前见到的活动)。系统不会 检查该活动的实例已经在返回栈中存在,每次启动都新建一个。当前返回栈为A->B(B为栈顶),新建活动B, 返回栈变为A->B->B。xml
standard模式有时并不合理,好比活动实例已经在栈顶了,再次启动时还需再建立一个实例, 这会形成资源的浪费。singleTop模式下,若是当前栈顶已是该活动实例,则认为能够直接使用,而再也不建立新的活动。当前返回栈为A->B(B为栈顶),新建活动B, 返回栈仍为A->B。
<!--AndroidManifest.xml--> <!--设置方式,launchMode --> <activity android:name=".MainActivity" android:launchMode="singleTop" android:label="AndroidDialog"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity>
singleTop模式能够避免重复建立栈顶活动的问题,可是若是启动活动不在栈顶,而以前已经建立过,仍是会重复建立。例如A->B->C,当前已有三个活动A、B、C,C位于栈顶,再建立B,返回栈变为A->B->C->B(另外一个实例)。singleTask模式可让返回栈中每一个活动只存在一个实例,若是发现当前须要启动活动已经在栈中,则直接使用,可是该活动之上的全部活动所有出栈;如没有发现,则建立新的实例。例如A->B->C,如此时建立活动B,则返回栈变为A->B(B存在,使用B,C出栈);若此时建立活动D,则返回栈变为A->B->C->D
singleInstance模式是四种启动模式中最复杂的,不一样于上述三种模式,指定为singleInstance模式的活动会启动一个新的返回栈来管理这个活动。例如当前有活动A、B、C,活动A、C为默认启动模式,B指定为singleInstance模式,首先新建A,A活动页面启动B,B启动C,此时的返回栈并非A->B->C,而是存在2个返回栈,一个是A->C,另外一个是B。此时按下BACK键返回,将从C返回到A,再按一次,A返回到B,按第三次,程序退出。即返回时,先清空栈A->C,再清空栈B。 singleInstance模式有什么应用场景呢?例如当前程序中某个活动容许其余活动调用,若是想多个程序共享该活动的一个实例A,那么每个程序都有一个返回栈,若使用前3种模式,该活动入栈时必然建立新的实例,没法实现实例共享。singleInstance能很好地解决这个问题。