Activity并非什么新鲜的东西,老生常谈,这里只是随笔记录一些笔记。java
每当提及Activity,感受最关注的仍是它的生命周期,由于要使咱们的应用程序更加健壮,客户体验更加良好,若是对生命周期不熟悉,那是不可能完成的任务。好了,言归正传,开始笔记,尽量用最精简的言语来阐述最实用的东西。android
准备写几篇文章,这是第一篇只谈生命周期的普通用法,不涉及到复杂点的知识,好比任何栈回退栈等操做。设计模式
一、一张来自谷歌官方文档的Activity的生命周期图:app
直接来个MainActivity,覆写以上全部方法并在方法里打印出Log日志,给定一个按钮,点击能够跳转到第二个Activity:ide
1 package com.lcw.rabbit.activitydemo; 2 3 import android.app.Activity; 4 import android.content.Intent; 5 import android.os.Bundle; 6 import android.util.Log; 7 import android.view.View; 8 import android.widget.Button; 9 10 public class MainActivity extends Activity { 11 12 private static final String TAG = "Rabbit"; 13 14 private Button mbButton; 15 16 @Override 17 protected void onCreate(Bundle savedInstanceState) { 18 super.onCreate(savedInstanceState); 19 setContentView(R.layout.activity_main); 20 mbButton = (Button) findViewById(R.id.bt_button); 21 mbButton.setOnClickListener(new View.OnClickListener() { 22 @Override 23 public void onClick(View v) { 24 startActivity(new Intent(MainActivity.this, SecondActivity.class)); 25 } 26 }); 27 28 Log.i(TAG, "1----------onCreate"); 29 } 30 31 @Override 32 protected void onStart() { 33 super.onStart(); 34 Log.i(TAG, "1----------onStart"); 35 } 36 37 @Override 38 protected void onResume() { 39 super.onResume(); 40 Log.i(TAG, "1----------onResume"); 41 } 42 43 @Override 44 protected void onPause() { 45 super.onPause(); 46 Log.i(TAG, "1----------onPause"); 47 } 48 49 @Override 50 protected void onStop() { 51 super.onStop(); 52 Log.i(TAG, "1----------onStop"); 53 } 54 55 @Override 56 protected void onRestart() { 57 super.onRestart(); 58 Log.i(TAG, "1----------onRestart"); 59 } 60 61 @Override 62 protected void onDestroy() { 63 super.onDestroy(); 64 Log.i(TAG, "1----------onDestroy"); 65 } 66 }
再来个SecondActivity,同样覆写以上全部方法:布局
1 package com.lcw.rabbit.activitydemo; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.util.Log; 6 7 public class SecondActivity extends Activity { 8 9 private static final String TAG = "Rabbit"; 10 11 @Override 12 protected void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 setContentView(R.layout.activity_second); 15 Log.i(TAG, "2----------onCreate"); 16 } 17 18 @Override 19 protected void onStart() { 20 super.onStart(); 21 Log.i(TAG, "2----------onStart"); 22 } 23 24 @Override 25 protected void onResume() { 26 super.onResume(); 27 Log.i(TAG, "2----------onResume"); 28 } 29 30 @Override 31 protected void onPause() { 32 super.onPause(); 33 Log.i(TAG, "2----------onPause"); 34 } 35 36 @Override 37 protected void onStop() { 38 super.onStop(); 39 Log.i(TAG, "2----------onStop"); 40 } 41 42 @Override 43 protected void onRestart() { 44 super.onRestart(); 45 Log.i(TAG, "2----------onRestart"); 46 } 47 48 @Override 49 protected void onDestroy() { 50 super.onDestroy(); 51 Log.i(TAG, "2----------onDestroy"); 52 } 53 54 55 }
二、Activity的流程之旅:(参照上面的流程图来理解)this
实验一:spa
当咱们进入第一个Activity的时候,咱们的Log日志依次打印出了:onCreate,onStart,onResume方法。设计
结论:3d
当咱们第一次启动Activity的时候会调用onCreate方法,而后在界面展现出来的时候调用了onStart方法,当用户获取焦点的时候调用onResume方法。
实验二:
当咱们按下Back键的时候,咱们的Log日志依次打印出了:onPause,onStop,onDestroy方法。
结论:
当Activity处于暂停(未被彻底遮挡,好比弹出对话框状态)的时候会调用onPause,当彻底不可见(被隐藏)的时候会调用onStop方法,当被销毁的时候会调用onDestroy方法。
实验三:
当咱们从新进入Activity,它依旧是调用onCreate,onStart,onResume方法,当咱们点击按钮跳转第二个Activity的时候,咱们的Log日志依次打印出了:onPause,而后第二个Activity打印出依次onCreate,onStart,onResume,而后第一个Activity再调用onStop方法。
结论:
当Activity处于暂停(未被彻底遮挡)的时候会调用onPause,而后启动第二个Activity,执行第二个Activity被建立的生命周期onCreate,onStart,onPause方法,当第一个Activity彻底不可见(被隐藏)的时候会调用onStop方法。
实验四:
当咱们按下Back键返回到第一个Activity的时候,Log日志依次打印出:第二个Activity的onPause,而后进入第一个Activity的onReStart,onStrat,onResume,而后第二个Activity调用了onStop,onDestroy。
结论:
当咱们按下Back键返回到第一个Activity的时候,第二个Activity会先调用onPause暂停,因为第一个Activity刚才没被调用onDestroy销毁,因此这里没有从新调用onCreate方法建立而是调用了onReStart方法,而后展现界面onStart,获取屏幕焦点onResume,而后第二个Activity被彻底覆盖执行onStop,而后被销毁onDestroy。
三、Activity设计模式之美
疑问1:
为何不能直接去启动第二个Activiity?
答:
其实你们能够这样来理解,当我启动一个正在执行音乐播放的Activity的时候,忽然有一个电话打进来了,电话也是一个Activity,那么在没有对第一个播放音乐的Activity进行暂停操做,就接通了电话,那么是否是咱们在边通话的时候还会边放着音乐啊?很显然这是不符合常理的。
疑问2:
当咱们启动别的Activity的时候,为何不先把一个Activity彻底销毁了,而后再去启动另外一个?
答:
仍是刚才打电话的例子,若是咱们直接彻底销毁了前面一个Activity,那么咱们在接电话的时候固然就是舒服,由于没有音乐吵你了,可是当咱们接完电话呢?咱们是否是又要去从新打开那个音乐的Activity,而后再重投开始听?而后恰好又来一个电话呢?我想这时的你应该要摔电话了。
再来,若是咱们直接去销毁了这个Activity,那恰好这个电话Activity因为不知名缘由发生问题呢?那么此时电话的Activity没启动起来,音乐的Activity又销毁了,那么用户的手机屏幕就会出现黑屏(闪屏),这点在用户体验上是很是很差的。
可能敏捷点的朋友已经想到这个暂停方法onPause的好处了,当电话来的时候,咱们去暂停音乐Activity的同时调用了onPause方法,咱们就能够在这个方法里面去记录一些东西了,好比当前音乐的播放进度,当咱们接完电话,回到音乐Activity的时候,咱们会调用(实验四)的方法,咱们能够在onRestart或者onResume中根据刚记录下来的播放进度去继续播放音乐。
因此Activity的生命周期这样去设计是很是合理的。
四、Activity交互实例
光说不练假把式,接下来上个示例,就以播放音乐为例子,注释很全,这里就再也不多说了,要注意的是,咱们进行了多媒体操做,咱们须要在onDestroy的时候释放资源对象,不然会占着内存,程序会愈来愈卡。
1 package com.lcw.rabbit.activitydemo; 2 3 import android.app.Activity; 4 import android.content.Intent; 5 import android.media.MediaPlayer; 6 import android.os.Bundle; 7 import android.util.Log; 8 import android.view.View; 9 import android.widget.Button; 10 11 public class MainActivity extends Activity { 12 13 private static final String TAG = "Rabbit"; 14 15 private Button mbButton; 16 private MediaPlayer mMediaPlayer; 17 private int mCurrentPosition; 18 19 @Override 20 protected void onCreate(Bundle savedInstanceState) { 21 super.onCreate(savedInstanceState); 22 setContentView(R.layout.activity_main); 23 //点击按钮跳转第二个Activity 24 mbButton = (Button) findViewById(R.id.bt_button); 25 mbButton.setOnClickListener(new View.OnClickListener() { 26 @Override 27 public void onClick(View v) { 28 startActivity(new Intent(MainActivity.this, SecondActivity.class)); 29 } 30 }); 31 32 //播放音乐 33 mMediaPlayer=MediaPlayer.create(this,R.raw.music); 34 mMediaPlayer.start(); 35 36 Log.i(TAG, "1----------onCreate"); 37 } 38 39 @Override 40 protected void onStart() { 41 super.onStart(); 42 Log.i(TAG, "1----------onStart"); 43 } 44 45 @Override 46 protected void onResume() { 47 super.onResume(); 48 if(mCurrentPosition!=0){ 49 //若是当前有记录进度,继续播放 50 mMediaPlayer.seekTo(mCurrentPosition); 51 mMediaPlayer.start(); 52 } 53 Log.i(TAG, "1----------onResume"); 54 } 55 56 @Override 57 protected void onPause() { 58 super.onPause(); 59 //记录当前进度 60 mCurrentPosition=mMediaPlayer.getCurrentPosition(); 61 mMediaPlayer.pause(); 62 Log.i(TAG, "1----------onPause"); 63 } 64 65 @Override 66 protected void onStop() { 67 super.onStop(); 68 Log.i(TAG, "1----------onStop"); 69 } 70 71 @Override 72 protected void onRestart() { 73 super.onRestart(); 74 Log.i(TAG, "1----------onRestart"); 75 } 76 77 @Override 78 protected void onDestroy() { 79 super.onDestroy(); 80 //释放资源 81 mMediaPlayer.release(); 82 mMediaPlayer=null; 83 Log.i(TAG, "1----------onDestroy"); 84 } 85 }
五、关于Activity数据状态的保存
因为手机是便捷式移动设备,掌握在用户的手中,它的展现方向咱们是没法预知的,具备不肯定性。平时咱们拿着手机多数为竖屏,但有时候咱们感受累了也会躺着去使用手机,那么这时手机屏幕的展现方向可能已经被用户切换成横屏,因为竖屏和横屏的界面宽高比例不一样,那么咱们的布局界面就会发生改变,因此是件很麻烦的事情,咱们须要去准备两套UI布局,固然不少时候咱们为了节省设计成本,只准备一套UI布局(竖屏或者横屏),使程序固定在一个方向,让其不跟随着屏幕的旋转而旋转。在这里咱们先不去管这些东西,咱们来看看当屏幕旋转的时候,Activity的生命周期是怎么走的:
实验五:
启动一个Activity,对屏幕进行翻转,观看生命周期的变化
结论:
在咱们翻转屏幕的时候,会销毁当前的Activity,而后重建Activity。
对Activity进行重建的时候,咱们的数据就会丢失,不少时候,当咱们切换到别的Activity的时候,须要保存当前Activity的状态或者是临时数据,那么咱们该怎么办呢?
咱们在Activity里再覆写这两个方法:
1 @Override 2 protected void onSaveInstanceState(Bundle outState) { 3 super.onSaveInstanceState(outState); 4 Log.i(TAG, "1----------onSaveInstanceState"); 5 } 6 7 @Override 8 protected void onRestoreInstanceState(Bundle savedInstanceState) { 9 super.onRestoreInstanceState(savedInstanceState); 10 Log.i(TAG, "1----------onRestoreInstanceState"); 11 }
而后咱们再来看下这两个方法是何时被调用的:
一、当正常进入退出的时候,生命周期依旧正常,这两个方法没有被调用:
二、当咱们正常进入一个Activity点击按钮跳转到别的Activity的时候,咱们会发现onSaveInstanceState在第二个Activity获取屏幕焦点(onResume)以后,在第一个Activity执行onPause以后,onStop以前调用了此方法,当从第二个Activity切换回来的时候就重复执行着实验四。
细心的朋友可能已经发现,onSaveInstanceState方法里有个Bundle类型的回调参数,在onCreate里面也有个Bundle类型的参数,没错,答案就在这里,若是咱们要对Activity的数据或者状态进行临时性的保存时,咱们能够在onSaveInstaceState存入参数,相似这样的:
1 @Override 2 protected void onSaveInstanceState(Bundle outState) { 3 super.onSaveInstanceState(outState); 4 outState.putString("name","Rabbit"); 5 Log.i(TAG, "1----------onSaveInstanceState"); 6 }
在onCreate里获取:
1 @Override 2 protected void onCreate(Bundle savedInstanceState) { 3 super.onCreate(savedInstanceState); 4 setContentView(R.layout.activity_main); 5 //获取保存数据 6 if (savedInstanceState!=null){ 7 Log.i(TAG, "I am "+savedInstanceState.get("name") ); 8 } 9 10 //点击按钮跳转第二个Activity 11 mbButton = (Button) findViewById(R.id.bt_button); 12 mbButton.setOnClickListener(new View.OnClickListener() { 13 @Override 14 public void onClick(View v) { 15 startActivity(new Intent(MainActivity.this, SecondActivity.class)); 16 } 17 }); 18 19 20 Log.i(TAG, "1----------onCreate"); 21 }
在onRestoreInstanceState里取:
1 @Override 2 protected void onRestoreInstanceState(Bundle savedInstanceState) { 3 super.onRestoreInstanceState(savedInstanceState); 4 //获取保存数据 5 if (savedInstanceState!=null){ 6 Log.i(TAG, "I am "+savedInstanceState.get("name") ); 7 } 8 Log.i(TAG, "1----------onRestoreInstanceState"); 9 }
无图无真相,来看下实验结果图,我进入了Activity对屏幕翻转,触发Activity重建,能够看到数据已经被保存了。
但这里有个疑问,当咱们不翻转屏幕,也就是不触发Activity重建的时候,咱们是没有执行onCreate,onRestoreInstanceState方法的,因此这个Bundle对象咱们不必定是能够拿到的,那数据保存不就变得很不可靠了吗?
没错,因为Activity重建的不肯定,因此saveInstanceState保存的数据通常都是临时性的,真正持久化操做咱们应该在onPause方法里操做。
这里额外的要提到一点,onRestoreInstanceState方法在两种状态下会被调用:
一、在Activity被覆盖或退居后台以后,系统资源不足将其杀死,而后用户又回到了此Activity,此方法会被调用;
二、在用户改变屏幕方向时,重建的过程当中,此方法会被调用。
六、关于屏幕方向改变Activity会重建的应对策略:
一、
指定为竖屏:在AndroidManifest.xml中对指定的Activity设置:
android:screenOrientation="portrait"
或者在onCreate方法中指定:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //竖屏
指定为横屏:在AndroidManifest.xml中对指定的Activity设置:
android:screenOrientation="landscape"
或者在onCreate方法中指定:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //横屏
二、
锁定屏幕虽然能够实现咱们想要的效果,但并非很好的一种作法,为了不这样销毁重建的过程,咱们能够在AndroidMainfest.xml中对对应的<activity>配置:
android:configChanges="orientation"
若是是Android4.0,则是:
android:configChanges="orientation|keyboardHidden|screenSize"
而后咱们在Activity里重写onConfigurationChanged方法:
1 @Override 2 public void onConfigurationChanged(Configuration newConfig) { 3 super.onConfigurationChanged(newConfig); 4 Log.i(TAG, "1----------onConfigurationChanged"); 5 }
这样Activity在翻转屏幕的时候就不会被销毁重建了,只是调用了onConfigurationChanged方法。
总结:
作工做中,你可能感兴趣的三个关键环① 完整生命周期② 可见生命周期③ 可交互生命周期
如图所示,图中的周期都是大的包括小的:
在实际工做中的使用
①onResume可见, 可交互.。把动态刷新的操做启动。
②onPause部分可见, 不可交互. 把动态刷新的一些操做, 给暂停了。
③onCreate 初始化一些大量的数据
④onDestroy 把数据给释放掉, 节省内存。
好了,今天先写到这里,关于Activity单单了解这些是远远不够的,下篇文章讲关于Activity的任务栈已经回退栈等操做。
做者:李晨玮
出处:http://www.cnblogs.com/lichenwei/本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文连接。正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,往后必有一番做为!旁边有“推荐”二字,你就顺手把它点了吧,相得准,我分文不收;相不许,你也好回来找我!