启动或结束一个Activity,我们就要跟它的生命周期打交道,安卓程序猿根据Activity的生命周期中各回调方法的触发时机处理对应的业务逻辑,以保证用户与页面之间能正常良好地交互。
这张图片多少人已经看烂了,不过我们依旧拿来参考Activity的生命周期。
新建一个Activity名为LifeCycleActivity。这是Activity的XML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<EditText
android:id="@+id/m_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="90dp"
android:layout_marginBottom="30dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:textSize="16sp"
android:ems="10" />
<Button
android:id="@+id/m_btnext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="跳转LifeJumpActivity" />
</LinearLayout>
然后是JAVA代码
public class LifeCycleActivity extends Activity {
private EditText medit;
private String s_txt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("LifeCycleActivity-", "onCreate");
setContentView(R.layout.activity_lifecycle);
medit = (EditText) findViewById(R.id.m_edittext);
findViewById(R.id.m_btnext).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent ite = new Intent(LifeCycleActivity.this, LifeJumpActivity.class);
startActivity(ite);
}
});
}
//是否按了键盘返回键
@Override
public void onBackPressed() {
Log.e("LifeCycleActivity-", "onBackPressed");
super.onBackPressed();
}
@Override
protected void onDestroy() {
Log.e("LifeCycleActivity-", "onDestroy");
super.onDestroy();
}
@Override
public void onLowMemory() {
Log.e("LifeCycleActivity-", "onLowMemory");
super.onLowMemory();
}
@Override
public void onTrimMemory(int level) {
Log.e("LifeCycleActivity-", "onTrimMemory");
super.onTrimMemory(level);
Log.e("onTrimMemory-", "level:"+level);
switch(level) {
case TRIM_MEMORY_COMPLETE:
Log.e("onTrimMemory-", "内存不足,并且该进程在后台进程列表最后一个,马上就要被清理");
break;
case TRIM_MEMORY_MODERATE:
Log.e("onTrimMemory-", "内存不足,并且该进程在后台进程列表的中部");
break;
case TRIM_MEMORY_BACKGROUND:
Log.e("onTrimMemory-", "内存不足,并且该进程是后台进程");
break;
case TRIM_MEMORY_UI_HIDDEN:
Log.e("onTrimMemory-", "内存不足,并且该进程的UI已经不可见了");
break;
case TRIM_MEMORY_RUNNING_CRITICAL:
Log.e("onTrimMemory-", "内存不足(后台进程不足3个),并且该进程优先级比较高,需要清理内存");
break;
case TRIM_MEMORY_RUNNING_LOW:
Log.e("onTrimMemory-", "内存不足(后台进程不足5个),并且该进程优先级比较高,需要清理内存");
break;
case TRIM_MEMORY_RUNNING_MODERATE:
Log.e("onTrimMemory-", "内存不足(后台进程超过5个),并且该进程优先级比较高,需要清理内存");
break;
}
}
@Override
protected void onPause() {
Log.e("LifeCycleActivity-", "onPause");
super.onPause();
s_txt = medit.getText().toString();
}
@Override
protected void onRestart() {
Log.e("LifeCycleActivity-", "onRestart");
super.onRestart();
}
@Override
protected void onResume() {
Log.e("LifeCycleActivity-", "onResume");
super.onResume();
medit.setText(s_txt);
}
/*onPostResume出现在onResume后,实际开发应用*/
/*@Override
protected void onPostResume() {
Log.e("LifeCycleActivity-", "onPostResume");
super.onPostResume();
}*/
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
Log.e("LifeCycleActivity-", "onRestoreInstanceState");
super.onRestoreInstanceState(savedInstanceState);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
Log.e("LifeCycleActivity-", "onSaveInstanceState");
super.onSaveInstanceState(outState);
}
@Override
protected void onStart() {
Log.e("LifeCycleActivity-", "onStart");
super.onStart();
}
@Override
protected void onStop() {
Log.e("LifeCycleActivity-", "onStop");
super.onStop();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
Log.e("LifeCycleActivity-", "onWindowFocusChanged");
// Log.e("LifeCycleActivity-", "onWindowFocusChanged-hasFocus:"+hasFocus);
super.onWindowFocusChanged(hasFocus);
}
/*屏幕的Activity加监听屏幕属性改变,发生改变则检查当前是否全屏状态。是全屏状态发送,全屏的广播消息,到监听应用触发操作。
*注意该判断在屏幕切换横竖屏是也会触发,需要根据实际情况过滤横竖屏切换的情况。*/
@Override
public void onWindowAttributesChanged(LayoutParams params) {
Log.e("LifeCycleActivity-", "onWindowAttributesChanged");
super.onWindowAttributesChanged(params);
if (WindowManager.LayoutParams.FLAG_FULLSCREEN == getWindow().getAttributes().flags) {
Log.e("LifeCycleActivity-","onWindowAttributesChanged()-FLAG_FULLSCREEN");
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
Log.e("LifeCycleActivity-", "onConfigurationChanged");
super.onConfigurationChanged(newConfig);
}
}
运行示例的代码在真机上,各个生命周期的过程如下:
1,Activity创建到显示:onCreate,onWindowAttributesChanged,onStart,onResume,onWindowFocusChanged
2,Activity从显示到关闭:onBackPressed(按下手机返回键),onPause,onWindowFocusChanged,onStop,onDestroy
3,显示的Activity按下home键:onPause,onWindowFocusChanged,onTrimMemory,onSaveInstanceState,onStop
4,按下home后再次回到此Activity:onRestart,onStart,onResume,onWindowFocusChanged
5,Activity里定义了一个EditText,用户按下了home键,Activity进入后台不可见,如果已经输入过文字,用户返回此Activity时希望EditText能显示输入的文字,此时就需要保存和读取文字。保存EditText的文字可以在onSaveInstanceState和onPause里保存,返回此Activity里时可以在onRestart,onStart,onResume里显示保存的文字,这里使用的是onPause保存,onResume显示,因为从前面可以看到Activity调用onPause和onResume较为普遍,当然你可以选择其他的时态,只要结果一样就行。
6,从此Activity跳转到新的Activity时:onPause,onWindowFocusChanged,onSaveInstanceState,onStop;
从新的Activity返回此Activity时:onRestart,onStart,onResume,onWindowFocusChanged
7,当Activity处于被覆盖或后台不可见状态,系统内存不足而干掉此Activity,而后用户返回了此Activity:
onCreate,onWindowAttributesChanged,onStart,onResume,onWindowFocusChanged
以上7种是比较常见的生命周期过程,接下来再讲一下各个时态方法调用的时机。
onCreate:Activity创建时被调用
onStart:Activity创建或者从后台重新回到前台时被调用
onRestart:Activity从后台重新回到前台时被调用
onResume:Activity创建或者从被覆盖、后台重新回到前台时被调用
onPostResume:出现在onResume后,实际开发应用较少
onPause:Activity被覆盖到下面或者锁屏时被调用
onStop:退出当前Activity或者跳转到新Activity时被调用
onDestroy:退出当前Activity时被调用,调用之后Activity就结束了
onWindowFocusChanged:Activity窗口获得或失去焦点时被调用,在onResume或onPause之后
onSaveInstanceState:Activity被系统杀死时被调用,例如:屏幕方向改变时,Activity被销毁再重建;
当前Activity处于后台,系统资源紧张将其杀死。另外,当跳转到其他Activity或者按Home键回到主屏时
该方法也会被调用,系统是为了保存当前View组件的状态。它在onPause之后被调用。
onRestoreInstanceState:Activity被系统杀死后再重建时被调用,例如:屏幕方向改变时,Activity被销毁再重建;当前Activity处于后台,系统资源紧张将其杀死,用户又启动该Activity。这两种情况下onRestoreInstanceState都会被调用,它的调用时机在onStart之后。
onWindowAttributesChanged:监听屏幕状态是否改变,检查当前屏幕是否全屏。Activity切换横竖屏时也会调用这个方法。
*** onLowMemory和onTrimMemory系统内存优化方法
当某个Activity处于后台不可见状态时,如果它带有较多Bitmap、数组、控件等占用内存较大的资源,此时在onLowMemory或onTrimMemory方法中重写方法来释放占用过多的内存。稍微注意以下几点:
1,OnLowMemory被回调时,已经没有后台进程;而onTrimMemory被回调时,还有后台进程。
2,OnLowMemory是在最后一个后台进程被杀时调用,一般情况是low memory killer 杀进程后触发;而OnTrimMemory的触发更频繁,每次计算进程优先级时,只要满足条件,都会触发。
3,通过一键清理后,OnLowMemory不会被触发,而OnTrimMemory会被触发一次。
具体又兴趣可以参考以下两篇文章:
应用内存优化之OnLowMemory&OnTrimMemory 点击打开链接
应用内存优化之OnLowMemory&OnTrimMemory 点击打开链接
*** Activity横竖切换屏幕生命周期
新建一个Activity,名为LifeJumpActivity,代码与LifeCycleActivity,只是多了重写监听屏幕横竖屏切换的方法onConfigurationChanged,下面是代码:
@Override
public void onConfigurationChanged(Configuration newConfig) {
Log.e("LifeJumpActivity-", "onConfigurationChanged");
super.onConfigurationChanged(newConfig);
switch (newConfig.orientation) {
case Configuration.ORIENTATION_PORTRAIT:
LifeJumpActivity.this.setContentView(R.layout.orientation_portrait);
Log.e("onConfigurationChanged", "切换到竖屏");
break;
case Configuration.ORIENTATION_LANDSCAPE:
LifeJumpActivity.this.setContentView(R.layout.orientation_landscape);
Log.e("onConfigurationChanged", "切换到横屏");
break;
}
}
可以看到,切换竖屏时重设布局orientation_portrait,切换横屏时则为orientation_landscape。
当次Activity并未在AndroidManifest.xml配置 android:configChanges="screenSize|orientation"时,Activity切换横竖屏时是会调用到生命周期的。
1,当Activity切换横竖屏时都会调用到如下生命周期:onPause,onSaveInstanceState,onStop,onDestroy,onCreate,onWindowAttributesChanged,onStart,onRestoreInstanceState,onResume,onWindowFocusChanged;而且此时setContentView方法无效。
2,当给此Activity添加了 android:configChanges="screenSize|orientation"属性后,Activity自动捕捉到设备屏幕方向和大小的改变,此时Activity只调用了onConfigurationChanged方法,而setContentView此时有效。注意Android4.0以后要使Activity切换横竖屏时不改变生命周期,必须为screenSize|orientation。
但是要注意,如果给Activity配置了android:screenOrientation属性,就会使android:configChanges设置的属性失效。
以上就是我复习总结的Activity生命周期,如有错误,敬请指正!