Android Activity生命周期
一、概念
1. 每个Activity实例都有其生命周期。在其生命周期内,activity在运行、暂停、停止三种可能的状态间进行转换。每次状态发生转换时,都有一个Activity方法将状态改变的消息通知给activity。
(此图来源于Android书籍权威指南)
(1). onCreate:表示Activit正在被创建,与其相对应的是onDestory。
(2). onRestart:表示Activity正在重新启动,一般情况下,Activity从不可见状态到可见状态。
(3). onStart:表示Activity正在被启动,即将开始,此时,Activity已经可见。与其相对应的是onStop。
(4). onResume:表示Activity已经可见,并且出现在前台并开始活动。与其相对应的是onPause。
(5). onPause:表示Activity正在被停止,正常情况下,紧接着onStop被回调。
(6). onStop:表示Activity即将停止,可以做一些稍微回收工作,但是不能太耗时。
(7). onDestory:表示Activity即将销毁,这是Activity生命周期最后一个回调,在这里可以做一些回收工作和资源释放。
PS:Activity整个生命周期中onCreate和onDestory是配对,分别代表时,Activity的创建和销毁,在整个周期中只能调用一次;从Activity是否可见来说,onStart和onStop是配对的,随着用户的操作或者设备屏幕的点亮和熄灭,这两个方法被多次调用,表示Activity的可见和不可见状态;从Activity是在前台来说,onResume和onPause是配对的,随着用户的操作和设备屏幕的点亮和熄灭,这两个方法被多次调用,表示Activity的在前台和在后台的状态。
在Activity类中,生命周期的方法:
1 public class ActivityDemo extends Activity 2 { 3 @Override // 表示Activity正在被创建 4 public void onCreate(Bundel savedInstanceState){} 5 6 @Override // Activity从不可见到可见状态 7 public void onRestart(){} 8 9 @Override // 表示Activity被启动,已经可见 10 public void onStart(){} 11 12 @Override // 表示Activity已经可见了,并且出现到前台开始活动 13 public void onResume(){} 14 15 @Override // 表示Activity正在被停止,正常情况下,紧接着onStop()被调用 16 public void onPuase(){} 17 18 @Override // 表示Activity即将停止,可以做一些稍微重量级的回收工作,但不能太耗时 19 public void onStop(){} 20 21 @Override // 表示Activity即将被销毁,这是Activity生命周期中,最后一个回调,可以做一些回收工作和最终的资源释放 22 public void onDestroy(){} 23 }
PS:在覆盖实现Activity生命周期方法时,在实现中,要先行调用超类(基类)的生命周期方法。Activity生命周期方法,不要自己调用,这个调用由android系统自己进行。Activity直接理解就是一个View从创建到显示,再到消失销毁的整个过程,在这个过程中,Activity状态在不停的转换。
- onDestroy()方法在Activity销毁前调用,用于销毁Activity中的对象。
- onFinish()方法是主动结束Activity的生命周期,在其中会去调用onDestroy()方法。
2. Activity切换时,生命周期方法执行顺序:
(1) 在一个Activity进入新建一个Activity时,生命周期方法执行:
- 第一个Activity的onPause();
- 第二个Activity的onCreate();
- 第二个Activity的onStart();
- 第二个Activity的onResume();
- 第一个Activity的onStop();
(2) 在新建的Activity返回到前一个Activity时,生命周期方法执行:
- 第二个Activity的onPause();
- 第一个Activity的onRestart();
- 第一个Activity的onStart();
- 第一个Activity的onResume();
- 第二个Activity的onStop();
- 第二个Activity的onDestroy();
(3) Activity进入后台,再进入前台:
- onPause();
- onStop();
- onRestart();
- onStart();
- onResume();
(4) ActivityA、ActivityB、ActivityC,其中ActivityB launchMode=singleTask,并A、B、C依次入栈后,ActivityC通过startActivity(...)启动ActivityB时生命周期:
1. ActivityC onPause();
2. ActivityB onRestart();
3. ActivityB onStart();
4. ActivityB onResume();
5. ActivityC onStop();
6. ActivityC onDestroy();
3. Activity实例在任务栈重用时,生命周期方法执行顺序:
- onPause();
- onResume();
PS: 配置Activity的lauchMode=singleTop。
二、Activity销毁原因
- android系统回收内存时,会将暂停或停止的Acitvity销毁。但不会销毁正在运行的Activity。
- 用户离开当前Activity管理的用户界面,Activity也会被销毁。
PS:Activity在暂停、停止及销毁前,会先调用onSaveInstanceState(...)方法。
三、多个Activity切换
通过startActivity(...)和startActivityForResult(...)进入另一个指定的Activity,Activity在finish()后,调用onDestroy()方法,销毁Activity对象。通过setResult(...)方法,在显示栈中顶层Activity时,标记从哪个Activity返回的。并且,传递返回的数据结构。
MainActivity.java:
1 public class MainActivity extends Activity 2 { 3 @Override 4 public void onCreate(Bundle savedInstanceState) 5 { 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.activity_main); 8 9 setupUI(); 10 } 11 12 public void setupUI() 13 { 14 LinearLayout navigation = new LinearLayout(this); 15 navigation.setOrientation(LinearLayout.VERTICAL); 16 TextView titleView = new TextView(this); 17 titleView.setText("Main Activity"); 18 LinearLayout.LayoutParams layoutParam = new LinearLayout.LayoutParams(LinearLayout 19 .LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); 20 layoutParam.gravity = Gravity.CENTER; 21 navigation.addView(titleView, layoutParam); 22 23 Button pushView = new Button(this); 24 pushView.setText("进入下一界面"); 25 pushView.setOnClickListener(new View.OnClickListener() 26 { 27 @Override 28 public void onClick(View v) 29 { 30 Toast.makeText(MainActivity.this, "进入下一个界面", Toast.LENGTH_SHORT).show(); 31 32 // intent 33 Intent intent = new Intent(); 34 intent.setClass(MainActivity.this, SecondActivity.class); 35 intent.putExtra("title", "第二个界面"); 36 startActivityForResult(intent, 11); 37 } 38 }); 39 navigation.addView(pushView, layoutParam); 40 addContentView(navigation, layoutParam); 41 } 42 43 @Override 44 protected void onActivityResult(int requestCode, int resultCode, Intent data) 45 { 46 Toast.makeText(this, "onActivityResult", Toast.LENGTH_SHORT).show(); 47 Intent intent = getIntent(); 48 Toast.makeText(this, "return result finish", Toast.LENGTH_SHORT).show(); 49 } 50 }
SecondActivity.java:
1 public class SecondActivity extends Activity 2 { 3 @Override 4 public void onCreate(Bundle savedInstanceState) 5 { 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.activity_second); 8 9 setupNavigation(); 10 } 11 12 public void setupNavigation() 13 { 14 LinearLayout navigation = new LinearLayout(this); 15 navigation.setOrientation(LinearLayout.HORIZONTAL); 16 17 String title = getIntent().getSerializableExtra("title").toString(); 18 ViewGroup.LayoutParams childParams = new ViewGroup.LayoutParams(LinearLayout 19 .LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); 20 21 Button back = new Button(this); 22 back.setText("返回"); 23 back.setOnClickListener(new BackLisenter()); 24 navigation.addView(back, childParams); 25 26 TextView titleView = new TextView(this); 27 titleView.setText(title); 28 navigation.addView(titleView, childParams); 29 30 LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout 31 .LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); 32 layoutParams.gravity = Gravity.CENTER; 33 addContentView(navigation, layoutParams); 34 Toast.makeText(this, title, Toast.LENGTH_SHORT).show(); 35 36 } 37 38 private class BackLisenter implements View.OnClickListener 39 { 40 @Override 41 public void onClick(View v) 42 { 43 // 设置返回数据结构 44 HashMap<String, String> maps = new HashMap<>(); 45 maps.put("id", "001"); 46 maps.put("name", "naray"); 47 Bundle bundle = new Bundle(); 48 bundle.putSerializable("items", maps); 49 Intent intent = new Intent(); 50 intent.putExtras(bundle); 51 // 指定返回到栈中顶层的Activity,标记从哪个Activity返回,并传递的数据结构 52 setResult(9, intent); 53 // 结构Activity生命周期 54 finish(); 55 } 56 } 57 }
四、异常情况下Activity的生命周期分析
4.1 资源相关的系统配置发生改变导致Activity被销毁并重新创建
比如,当前Activity保处于竖屏状态,如果实然旋转屏幕,由于系统配置发生了改变,在默认情况下,Activity就会被销毁并且重新创建。当然,这一情况也是可以被阻止的,不让系统重新创建Activity。
在默认情况下,Activity不做特殊处理,当系统配置发生改变后,Activity就会被销毁,其中的onPause、onStop、onDestory方法会被调用,同时,由于Activity是被异常终止的,系统会调用onSaveInstanceState方法保存当前Activity的场景状态。这个方法在onStop方法调用之前被调用,与onPause方法没有既定的时序关系,即可以在onPause之前,也可以在onPause之后被调用。
PS:onSaveInstanceState方法只会在Activity异常情况下被终止时被系统调用,在正常情况下Activity的终止是不会被系统调用的。
在Activity异常终止销毁后,重新创建系统会调用onRestoreInstanceState方法,并且会将Activity被异常终止销毁时,调用onSaveInstanceState方法时,存储的Bundle对象作为参数传递给onRestoreInstanceState和onCreate方法。因此,可以通过onRestoreInstanceState和onCreate方法判断Activity是否是被重新创建的,如果被重新创建了,就取出存储的数据并且恢复之,从时序上来说,onRestoreInstanceState调用时机是在onStart方法调用之后,系统会调用onRestoreInstanceState方法。
同时,要知道在onSaveInstanceState和onRestoreInstanceState方法,系统默认做了一些事情用于帮忙恢复Activity在创建后,恢复Activity场景状态。
Activity异常情况下的销毁和重建(示例为屏幕旋转的情况):
4.1.1 屏幕旋转时,禁止重建Activity
通过设置configChanges配置禁止在异常情况下,重建Activity。
1 <activity 2 android:name=".Activity.MainActivity" 3 android:configChanges="orientation|screenSize|keyboardHidden"> 4 </activity>
然后,重写onConfigurationChanged方法:
@Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); Log.d(TAG, "onConfigurationChanged"); }
4.2 资源内存不足导致低优先级的Activity被销毁
这种情况下的数据存储和数据恢复与4.1情况完全一致。在这里我们描述一下Activity的优先级情况。Activity的优先级按照从高到低可以分为三种情况:
(1). 前台Activity,正在与用户交互的Activity,优先级最高。
(2). 可见但非前台Activity,比如Activity中弹出一个对话框,导致Activity可见,但是Activity位于后台,无法与用户直接交互。
(3). 后台Activity,已经被暂停Activity,即执行了onStop方法,优先级最低。