四大组件之Activity(上)——Activity的生命周期、系统回收、系统配置改变的影响
2016-05-17 15:08
603 查看
第1节 Activity的使用
Activity几乎是每个应用必有的组件,所以任何安卓应用的开发几乎都是从
Activity开始的。
比如,你希望设计一个计算器应用,要呈现这个计算器的功能(显示出计算器的样子,实现计算的能力)一定会在这个应用中创建一个
Activity,让这个
Activity展示的界面就是计算器。
所以使用Android Studio创建工程以后,会默认为我们创建一个
Activity组件,它继承自Android SDK的
Activity类。
class CalulatorActivity extends Activity { ...... }
新创建的Activity—CalulatorActivity作为安卓的四大组件之一,一定要在这个应用的配置文件manifest.xml中声明自己的存在,否则系统会不认识这个组件,当你启动它的时候就会报错。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.anddle.calculator"> <application android:icon="@mipmap/ic_launcher" android:label="@string/app_name"> <!--为应用声明一个Activity--> <activity android:name=".CalulatorActivity"> ...... </activity> </application> </manifest>
第2节 Activity的生命周期
每一个Activity都有它的生命周期,体现了它从诞生到消亡的各个阶段。下图为我们展示了Activity整个生命的过程,这是安卓官方提供的Activity生命周期图。
2.1 生命各个时期的回调
Activity每进入到一个生命的阶段,就会调用这些状态对应的函数。@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override protected void onDestroy() { super.onDestroy(); } @Override protected void onResume() { super.onResume(); } @Override protected void onPause() { super.onPause(); } @Override protected void onStart() { super.onStart(); } @Override protected void onStop() { super.onStop(); } @Override protected void onRestart() { super.onRestart(); }
如果我们在代码中继承了Activity类,并覆盖了这些函数,我们就能感知到Actvity生命状态的转换,并在这个转换的时刻让Activity做对应的处理。
比如在Activity创建的时候,让它调用我们的代码,完成界面的布局;在Activity销毁的时候,让它调用我们的代码,完成界面资源的释放。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //进行界面的布局 setContentView(R.layout.activity_main); ...... } @Override protected void onDestroy() { super.onDestroy(); //释放一些界面可能占用的资源 ...... }
2.2 Activity的状态
接下来,我们详细介绍下Acivity的各个阶段。这些阶段都是成对出现的。根据不同的标准,我们将它们分成三类:全生命周期:这是Activity的从创建到销毁的整个阶段,从
onCreate()开始到
onDestroy()结束。
可见生命周期:这是Activity能被用户看到的整个阶段,这里说的能被看到包括了“虽然被显示但是不能与用户交互”的情况,例如你正在微信聊天,突然系统弹出来一个对话框类型的Activity,提示你电量不足,这时微信界面被挡在后面,不能和用户交互了,但是你还能看到。从
onStart()开始到
onStop()结束。
前台生命周期:这是Activity可以和用户进行交互的阶段。从
onResume()开始到
onPause()结束。
2.3 Acivity常见的切换周期
2.3.1 完全周期
从一个Activity创建出来,到显示,再到用户按返回键主动退出销毁这个Activity,它将经历:onCreate()->
onStart()->
onResume()->
用户可以与Activity交互,用户按返回键主动退出->
onPause()->
onStop()->
onDestroy();
2.3.2 Activity启动另一个Activity
Activity A创建出来,并显示;然后Activity A启动另一个Activity B,B创建出来,并显示,它将经历:Activity A onCreate()->
Activity A onStart()->
Activity A onResume()->
用户可以与Activity A交互,然后Activity A启动另一个Activity B,
Activity A onPause()->
Activity B onCreate()->
Activity B onStart()->
Activity B onResume()->
Activity A onSaveInstanceState()->
Activity A onStop()->
Activity A被隐藏,用户可以与Activity B交互;
2.3.3 Activity屏幕旋转
如果一个Activity从创建出来,到显示,然后旋转,那么它将经历:onCreate()->
onStart()->
onResume()->
用户可以与Activity交互,此时屏幕进行旋转,从竖屏变横屏->
onPause()->
onSaveInstanceState()->
onStop()->
onDestroy()->
onCreate()->
onStart()->
onRestoreInstanceState()->
onResume()->
用户可以与Activity交互;
在周期变化的过程当中,加入了
onSaveInstanceState()和
onRestoreInstanceState()。虽然它们不是
Activity周期的一部分,但是对它们对回调在
Activity的各种切换扮演了非常重要的角色--提供了保存
Activity数据的时机。
第3节 Activity的系统回收
在Activity生命的周期中,安卓系统可能直接回收Activity。系统回收Activity有两种常见的情况,系统资源紧张;
屏幕的旋转;
3.1 资源紧张
当系统资源紧张的时候,例如你打开了很多应用,系统中的可用内存很少了。这是安卓系统会采用一个策略来回收系统中的资源。对于那些没有显示或者虽然显示了、但却没有和用户做交互的Activity们,系统会优先回收那些没有显示的Activity(例如在onStop()状态下的Activity);
如果回收那些资源以后,发现资源还是不够用,就会回收虽然显示了、但却没有和用户做交互的Activity(例如在onPause()状态下的)。
这里会遇到一个问题:假如Activity A启动了Activity B之后,系统发现内存不足,在回收了其它所有资源后,它不得不继续回收Activity A。
3.1.1 产生的问题
此时与Acitity B正在交互的用户,点击了“返回”按钮,按照道理,应该显示Activity A才对,但是系统已经回收了Activity A。这时该怎么办呢?系统遇到这种情况就会重新创建Activity A,重新调用它的onCreate()。
不过这里又会遇到另一个很现实的问题:如果之前的Activity A上面用户正输入了一些东西,例如他的名字和邮箱地址,或者是已经编辑了很长一大段的文字,如果系统onCreate的话,这些输入的东西就会被清除掉了。这可怎么办呢?
3.1.2 解决办法
安卓系统为我们提供了一个这种情况下数据的重建机制:在Activity被放到后台运行的时候使用onSaveInstanceState()回调函数来保存这些数据,
@Override protected void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); //将要保存的数据,例如撰写的文档的字符串,保存到savedInstanceState变量当中 }
在Activity被重建的时候,使用
onRestoreInstanceState()回调函数来恢复这些数据
@Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); //将需要恢复的数据,例如文档字符串,从savedInstanceState变量中取出,设置到界面上 }
需要注意的是,
onSaveInstanceState()与
onRestoreInstanceState()在Activity周期切换过程中并不一定会被调用,只是在这种Activity异常流程处理时(Activity被系统回收、config信息变化等情况),才会被调用到。
3.2 屏幕旋转
屏幕旋转时,Activity的生命周期也将发生变化。如果一个Activity从创建出来,到显示,然后旋转,那么它将经历:
onCreate()->
onStart()->
onResume()->
用户可以与Activity交互,此时屏幕进行旋转,从竖屏变横屏->
onPause()->
onSaveInstanceState()->
onStop()->
onDestroy()->
onCreate()->
onStart()->
onRestoreInstanceState()->
onResume()->
用户可以与Activity交互;
可以看到,旋转的时候
onCreate()函数会被再次调用。在这里,如果拥有横屏布局文件,
onCreate()中的
setContentView()将会使用横屏的布局,如果没有,依然使用默认的布局文件。
3.2.1 产生的问题
如果Activity从竖屏变成横屏,那么会先执行onDestroy(),再进行一次
onCreate()创建的过程。这意味着之前界面上显示的数据需要重新刷新一次。
假如之前刷新这些数据需要花费很长的时间,那就有必要认真的思考如何避免数据的再次刷新。
3.2.2 解决方法
解决屏幕旋转时Activity被create两次的方法有两种。用
onSaveInstanceState()和
onRestoreInstanceState()可用用来保存和还原这些数据;
在
AndroidManifest.xml文件中,给这个Activity组件加上
android:screenOrientation="orientation|screenSize"的属性就可以了;
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.anddle.anddleplayer"> <application ......> <activity android:name=".VideoListActivity" android:configChanges="orientation|screenSize"> </activity> ...... </application> </manifest>
这种Activity从创建出来,到显示,然后旋转,那么它将经历:
onCreate()->
onStart()->
onResume()->
用户可以与Activity交互,此时屏幕进行旋转,从竖屏变横屏->
onConfigurationChanged();
如此一来,这个Activity在旋转时就不会重走销毁、创建的过程了,而只是在旋转后经历一个
onConfigurationChanged()。这种情况下,如果存在它对应的横屏布局文件,那么这个布局也不会被使用到,因为
onCreate()并没有被调用到。
第4节 系统设置改变
当设备的系统设置发生变化时,例如横竖屏切换、语言变化,可以被Activity感知到。4.1 监听系统设置改变
系统设置发生变化可以通知到Activity,在
AndroidManifest.xml文件当中,给对应的Activity标签,添加
android:configChanges属性,例如
<activity android:name=".AlertActivity" <!--指定Activity关注的系统变化类型,这里只表示关注屏幕大小是否变化-screenSize、 设备方向是否变化-orientation--> android:configChanges="screenSize|orientation"> </activity>
在需要在实现Activity的代码中做出相应的修改:
@Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //从newConfig中获取感兴趣的系统配置变化事件,例如屏幕方向是否变化,系统语言是否变化等等 if(Configuration.ORIENTATION_PORTRAIT == newConfig.orientation) { } }
在manifest中指定关注的是
screenSize和
orientation,那么当手机从横屏变化成竖屏(或者竖屏变化成横屏)的时候,这个函数就会被调用,就可以在这里添加我们需要的代码。
系统变化的种类很多,除了
screenSize和
orientation还有:
keyboardHidden
locale
fontScale等等。
4.2 设备旋转
我们可以用两种方法处理设备的旋转,让Activity不跟随设备方向的旋转而旋转,它只有竖屏(或只有横屏)的界面。要做到这一点很容易,在
AndroidManifest.xml文件中,给这个Activity组件加上
android:screenOrientation="portrait"(保持竖屏)或者
android:screenOrientation="landscape"
(保持横屏)的属性就可以了;
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.anddle.anddleplayer"> <application ......> <activity android:name=".VideoListActivity" android:screenOrientation="landscape"> </activity> ...... </application> </manifest>
让Activity跟随设备方向的旋转而旋转。
采用章节3.2中介绍的方法。
相关文章推荐
- 编程基本功训练:流程图画法及练习
- 嵌入式为什么选择C语言? (面试)
- struts.xml配置详解
- 判断图片的类型(图片是data类型 )
- 使用泛型为不同类型的列表分页
- NOIP2012day2题解
- HTTP协议及其POST与GET操作差异 & C#中如何使用POST、GET等
- 4-认识HTML标签(3)
- 2. npm 的使用
- iOS LaunchScreen设置启动图片 启动页停留时间
- MySQL check the manual that corresponds to your MySQL server version for the right syntax错误
- Maximum Subarray
- android5.0以上对于APP_SWITCH和HOME键的处理
- 大公司在github的开源代码
- jquery的学习
- 给程序员的忠告(转)
- web开发常见问题集锦
- [IOS/翻译]GCD-3 Using Dispatch Groups
- 周记 2016.4.17
- bzoj 4590: [Shoi2015]自动刷题机