Activity 生命周期详解,android 游戏开发实践指南
以实际案例来详细了解 Activity 的声明周期。
问题一:Activity A 启动另一个 Activity B 会回调哪些方法?如果 Activity B 是完全透明呢?如果启动的是一个 Dialog 呢?
========================================================================
A 启动 B:A 的 onPause() -->B 的 onCreate()-->onStart()-->onResume()-->A 的 onStop()
A 启动 B,B 完全透明:A 的 onPause() -->B 的 onCreate()-->onStart()-->onResume()
A 界面启动一个 dialog:如果是单纯的一个 dialog,并不调用生命周期,如果启动的是一个以 dialog 形式展示的 activity,同上。
Demo 逻辑介绍:
FirstActivity:主 Activity
1、启动 SecondActivity:普通的 Activity
A 启动 B:A 的 onPause() -->B 的 onCreate()-->onStart()-->onResume()-->A 的 onStop()
问题:A 的生命周期为什么会先调用 onPause(),在 B 完全展示后再去调用 A 的 onStop()方法,为什么要这样设计?
答:onPause 的调用是“Another activity comes in front of the activity”,即另一个 activity 跑到前台来的时候,前一个 activity 的 onPause 方法会被调用。
onStop 的调用是“The activity is no longer visible”,也就是完全不可见的时候调用的,这个完全不可见真的就是指视觉上的完全看不到而已,无论是按 home 键返回桌面,还是启动另一 activity 把原 activity 完全遮住,都会调用 onStop。但是当启动的 activity 是透明的时候,原 activity 只会进入 onPause 状态,而不会走到 onStop 状态,因为原 acitivity 还是可见的,虽然逻辑上被遮住了,但是视觉上确实是可见的,这一点要注意。
2、启动 ThirdActivity:完全透明的 Activity
A 启动 B,B 完全透明:A 的 onPause() -->B 的 onCreate()-->onStart()-->onResume()
3、启动 FourActivity:以 Dialog 形式展示的 Activity
A 启动 B,B 以 Dialog 形式展示:A 的 onPause() -->B 的 onCreate()-->onStart()-->onResume()
4、启动一个 Dialog
A 界面启动一个 dialog:如果是单纯的一个 dialog,并不调用生命周期
问题二:谈谈 onSaveInstanceState()方法?何时会调用?
====================================
a.出现时机:异常 情况下 Activity 重建,非用户主动去销毁
b.系统异常终止时,调用 onSavaInstanceState 来保存状态。该方法调用在 onStop 之前,但和 onPause 没有时序关系。
c.Activity 被重新创建时,调用 onRestoreInstanceState(该方法在 onStart 之后),并将 onSavaInstanceState 保存的 Bundle 对象作为参数传到 onRestoreInstanceState 与 onCreate 方法。
5、启动 FiveActivity
在该界面设置一个按钮(点击触发空指针异常),点击按钮界面崩溃退出。
结果:在此种情况下不会触发 onSaveInstanceState()方法!
另外:横竖屏切换也不会触发 onSaveInstanceState()方法! 但是会触发 onRestoreInstanceState()方法。
[activity 中的 onSaveInstanceState 方法的调用时机](
)?在该文章中所列举的几种方法都尝试过了,但是都没有触发 onSaveInstanceState()方法。
问题三:横竖屏切换时,Activity 的声明周期如何变化
============================
如果不做任何配置:
会销毁当前 Activity 然后在新创建一个,生命周期如下:
onPause() --> onStop() --> onDestory() --> onCreate()-->onStart()-->onResume()
Adnroid 3.2 以后的 SDK 需要设置: android:configChanges="orientation|keyboardHidden|screenSize"
manifest 中为相应的 Activity 设置 android:configChanges 属性即可
Andorid 3.2 以前的 SDK 可以使用如下配置
android:configChanges="orientation|keyboardHidden"
而 Adnroid 3.2 以后的 SDK 必须添加一个 screenSize 属性,具体如下
android:configChanges="keyboardHidden|orientation|screenSize"
或者
android:configChanges="orientation|screenSize"
对 android:configChanges 的总结
1、不设置 Activity 的 android:configChanges 时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次(在三星 4.0 设备上切横屏和竖屏都是执行一次,而并非这里说的有执行两次的情况);
2、设置 Activity 的 android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次;
3、设置 Activity 的 android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行 onConfigurationChanged 方法。
注:上述描述是在 Android3.2 以前,如果缺少了 keyboardHidden 选项,不能防止 Activity 的销毁重启,也就不能执行 onConfigurationChanged 方法了。在 3.2 之后,必须加上 screenSize 属性才可以屏蔽调用 Activity 的生命周期(一些设备上可以不需要 keyboardHidden,只要 screenSize 就可以了,保守起见还是继续保留 keyboardHidden 吧)。
源码展示:
=====
1、style.xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="BtnCommon">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">60dp</item>
<item name="android:textAllCaps">false</item>
<item name="android:textSize">16sp</item>
</style>
<style name="dialogStyle" parent="Theme.AppCompat.Light.Dialog">
<item name="windowNoTitle">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowFrame">@null</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
<style name="TranslucentTheme" parent="Theme.AppCompat.Light.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowAnimationStyle">@android:style/Animation</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
</resources>
2、AndroidManifest.xml
<activity android:name=".lifecycle.FirstActivity" />
<activity android:name=".lifecycle.SecondActivity" />
<activity
android:name=".lifecycle.ThirdActivity"
android:theme="@style/TranslucentTheme" />
<activity
android:name=".lifecycle.FourActivity"
android:theme="@style/dialogStyle" />
<activity
android:name=".lifecycle.FiveActivity"
android:configChanges="orientation|keyboardHidden|screenSize" />
3、FirstActivity
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
ButterKnife.bind(this);
LogUtils.e("onCreate");
}
@OnClick({R.id.btn1, R.id.btn2, R.id.btn3, R.id.btn4, R.id.btn5})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.btn1://1、启动 SecondActivity:普通的 Activity
startActivity(new Intent(this, SecondActivity.class));
break;
case R.id.btn2://2、启动 ThirdActivity:完全透明的 Activity
startActivity(new Intent(this, ThirdActivity.class));
break;
case R.id.btn3://3、启动 FourActivity:以 Dialog 形式展示的 Activity
startActivity(new Intent(this, FourActivity.class));
break;
case R.id.btn4://4、启动一个 Dialog
new AlertDialog.Builder(this).setIcon(R.mipmap.ic_launcher).setTitle("最普通 dialog")
.setMessage("我是最简单的 dialog").setPositiveButton("确定(积极)", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(FirstActivity.this, "确定按钮", Toast.LENGTH_LONG).show();
}
}).setNegativeButton("取消(消极)", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(FirstActivity.this, "关闭按钮", Toast.LENGTH_LONG).show();
dialogInterface.dismiss();
}
}).create().show();
break;
case R.id.btn5://5、启动 FiveActivity: 在该界面设置一个按钮,点击按钮界面崩溃退出。
startActivity(new Intent(this, FiveActivity.class));
break;
}
}
@Override
protected void onStart() {
super.onStart();
LogUtils.e("onStart");
}
@Override
protected void onResume() {
super.onResume();
LogUtils.e("onResume");
}
@Override
protected void onPause() {
super.onPause();
LogUtils.e("onPause");
}
@Override
protected void onStop() {
super.onStop();
LogUtils.e("onStop");
}
@Override
protected void onRestart() {
super.onRestart();
LogUtils.e("onRestart");
}
@Override
protected void onDestroy() {
super.onDestroy();
LogUtils.e("onDestroy");
}
@Overri
de
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
LogUtils.e("onSaveInstanceState");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
LogUtils.e("onRestoreInstanceState");
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.gs.sumok2.lifecycle.FirstActivity"
android:orientation="vertical">
<Button
android:id="@+id/btn1"
style="@style/BtnCommon"
android:text="SecondActivity" />
<Button
android:id="@+id/btn2"
style="@style/BtnCommon"
android:text="ThirdActivity" />
<Button
android:id="@+id/btn3"
style="@style/BtnCommon"
android:text="FourActivity" />
<Button
android:id="@+id/btn4"
style="@style/BtnCommon"
android:text="Dialog" />
<Button
android:id="@+id/btn5"
style="@style/BtnCommon"
android:text="FiveActivity" />
</LinearLayout>
4、SecondActivity
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
LogUtils.e("onCreate");
}
@Override
protected void onStart() {
super.onStart();
LogUtils.e("onStart");
}
@Override
protected void onResume() {
super.onResume();
LogUtils.e("onResume");
}
@Override
protected void onPause() {
super.onPause();
LogUtils.e("onPause");
}
@Override
protected void onStop() {
super.onStop();
LogUtils.e("onStop");
}
@Override
protected void onRestart() {
super.onRestart();
LogUtils.e("onRestart");
}
@Override
protected void onDestroy() {
super.onDestroy();
LogUtils.e("onDestroy");
}
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.gs.sumok2.lifecycle.SecondActivity">
评论