2024年8月24日发(作者:韦绢)
android activity
详解一:概述
概述
如何创建Activity
实现用户界面
在名单文件中声明activity
使用intent过虑器
启动一个Activity
启动一个acitvity并得到结果
关闭Activity
概述
Activities 是一个程序的组件之一。它的主要功能是提供界面。
一个程序一般由多个Activity组成,各activities之间关系很松散,它们之间没有
直接的关联。必须有一个activity被指定为主activity,它是程序启动时首先显示的界
面。每个activity都可以随意启动其它的activity。每当一个activity被启动,则前一
个activity就被停止。一个程序中的所有启动的activity都被放在一个栈中,所以被停
止的activity并没有销毁,而在存于棧中。新启动的activity先被存放于栈中,然后获
得输入焦点。在当前活动的activity上点返回键,它被从棧中取出,然后销毁,然后
上一个activity被恢复。
当一个activity因为新的activity启动而被停止时,它会收到状态变化的通知,这
样的变化有多个,每个都会引起系统调用一个相应的回调方法以通知activity,这些
回调方法被统称为“生命周期回调方法”。这些回调方法分别在Activity被创建、停
止、恢复、销毁时被调用。
如何创建Activity
1 从类activity继承。
2 实现“生命周期回调方法”
两个最重要的方法是:
onCreate()--这个是必须实现的函数,在其中做初始化工作。记住:你必须在此
函数中调用setContentView()函数的设置Activity的界面。
onPause()--这个虽然很重要,但不是要必须实现的。此函数在用户离开Activity
时被调用(这一般并不表示Activity要被销毁了)。在这个函数中,你一般需要提交那
些需保存状态的数据(因为用户可能不再返回到这个Activity)。其它回调方法视情况
实现。
实现用户界面
此处的用户界面指的就是activity上的控件们。所有的控件都从View类派生,
所以可以把它们都称为View。每个控件占据一个矩形区域。
控件又分为以下两类:Widgets是完成特定功能的控件,比如button,text
field,checkbox 等。Layouts是容纳Widgets控件并进行排版的控件,当然,Layout
中还可以容纳Layout。Widgets从View类派生,Layouts从ViewGroup类中派生,
开发者可以从View或ViewGroup派生创造自己的控件。
定义界面的最好的方法是使用XML格式的layout文件,它作为资源保存在工程
中,可以在工程的res/layout下面找到这些XML文件。通过这种方式就做到了代码
与界分离。把layout 下的某个XML设置为某个Activity的界面,需调用Activity的
setContentView(),把XML的资源ID作为参数传入即可。
在名单文件中声明activity
为了能让系统操作你的Activity,你必须在工程的名单文件中声明它。例如:
...
...
当然有很多属性可以设置给Activity,比如label,icon或主题等等。详情请查看
注意看
最前面有个”.”,如果你把它忘了,程序运行就会出错,而你很难找出错误的原因。
其次,不论你是Activity是只内部使用还是外部使用,都要去名单文件中注册,否则
依然会出现莫名其妙的错误,只是在内部使用时,不需要为acitivity增加意图过滤器。
使用intent过虑器
可以为一个
过虑器的目的是告诉其它组件如何启动这个Activity。当你使用ADT创建一个新工程
时,根Activity被自动创建,它已具有两个意图过虑器,一个意图过虑器声明这个
Activity负责响应“main”action;另一个过虑器声明这个Activity须被置
于”launcher”类别之下。一般是这个样子:
如果你写的程序中的Activity不需被其它程序调用,那么不需为这个Activity增
加任何意图过滤器。但程序中必须有一个Activity被指定为”main” Action
和”launcher” category。你自己程中的 Activity可以用更直接的方式调用。
然而,如果你想让你的Activity被其它程序调用,那么你需要为它增加意图过滤
器。这些过意图滤器包括
activity响应何种类型的intent。
启动一个Activity
你可以用startActivity()启动一个activity,它有一个参数是intent,你需要在这个
intent中指明要调用的activity。Intent中你可以明确地指定要启动的activity,或只指
定activity的类型,此时系统会为你挑选一个合适的activity,这个activity可能位于
其它程序中,也可能位于你自己的程序中。Intent中可以带一坨被新activity使用的
数据(相当于参数传递)。
在你的程序内部,如果需要启动一个内部的activity,你需在intent中明确指定
新activity的类名。例如:
Intent intent = new Intent(this, );
startActivity(intent);
SignInActivity是要启动的activity类。
然而,你的程序可能想执行自身没有提供的功能,比如发出邮件,发送短信息等。
此时,需要启动其它程序提供的activity。此时就体现出intent的真正价值来了:它
可以很容易地启动其它程序提供的activity,你只需要在intent中指定你要执行的动
作,然后调用 startActivity() ,系统就会跟据你的需要,为你选择一个合适的activity,
并启动它。如果同时有多个activity可以执行这动作,那么用户可以选择哪个被使用。
例如,你想让用户发送一个电子邮件,你可以创建以下的Intent:
Intent intent = new Intent(_SEND);
ra(_EMAIL, recipientArray);
startActivity(intent);
putExtra()是设置扩充数据的,.EXTRA_EMAIL表明第二个参数recipientArray
里面放的是多个email地址。当发邮件的程序被启动并接收到这个intent时,它就把
邮件地址们放到它的Acitivity界面的“to”控件中。当用户发送完毕返回时,你的
activity就恢复运行(resume)。可以看到,启动另外一个程序是多么的容易。
启动一个acitvity并得到结果
有时,你可能想从你启动的activity获得其执行后返回的结果。此时你可以用方
法startActivityForResult()来启动新acitivity(不再是startActivity了)。然后,你的程
序还需要定义回调方法onActivityResult()。当新activity运行结束时,它把一个intent
返回给你的程序,这个intent是在onActivityResult()中被接收。
例如:你想让用户打开通讯录,从中选择一个联系人,然后你取得用户所选的联
系人,对之进行处理。以下是示例代码:
private void pickContact() {
//Create anintent to "pick" a contact, as defined by the content provider URI
Intent intent =new Intent(_PICK, T_URI);
startActivityForResult(intent, PICK_CONTACT_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, intresultCode, Intent data) {
// If the requestwent well (OK) and the request was
PICK_CONTACT_REQUEST
if (resultCode== _OK && requestCode ==
PICK_CONTACT_REQUEST) {
// Perform aquery to the contact's content provider for the contact's name
Cursorcursor = getContentResolver().query(a(),new
String[]{Y_NAME}, null, null, null);
if(First()) { // True if the cursor is not empty
intcolumnIndex =
umnIndex(Y_NAME);
String name =ing(columnIndex);
// Dosomething with the selected contact'
}
}
}
此例子展示了在onActivityResult()中的基本逻辑流程。首选检查所启动的
Activity是否正确运行,resultCode为_OK表示正常,其次,查看
requestCode是否与当时请求的一致,即是否为PICK_CONTACT_REQUEST。都
通过后,开始操作返回的数据,也就是data参数。
Data是这样处理的,用ContentResolver向内容提供者发出请求,这个请求会
返回一个游标,通过这个游标读取数据,这很像数据库表的操作。要理解此处,请查
阅Content Providers一节。
关闭Activity
Activity可以内部调用finish()方法关闭它自己,也可以调用finishActivity()方法关
闭其它的activity。
注意:大多数情况下,你不应主动结束一个activity。系统掌管着activity的生命,
所以你也不必结束自己的activity。使用上述方法会破坏用户体验。除非你觉得很必
要时,否则就不要做!
android activity
详解二:
Activity
的生命周期
管理Activity的生命周期
实现生命周期回调
管理Activity的生命周期
通过实现activity的生命周期回调方法来管理你的activity,是创造既稳定又灵活的
activity的关键。Activity的生命周期直接受到相关的其它activity和它的任务以及所在栈的
影响。
一个activity可生存在三种基本的状态中:
Resumed
Activity位于屏幕的最上层,并具有用户焦点,用户可以操作它。(此状态有时也被认为
是“运行”状态)。
Paused
Activity B位于最上层并其获得输入焦点,acitvity A位于其下一层,但activity A依然可
见,此时activity A就处于Paused状态。Activity A可见的原因可能是activity B是半透明
的,或acitvity B不覆盖整个屏幕。此状态的activity依然是“活”的,因为它还是位于内
存中,并且它被窗口管理器所管理。它只要获取到CPU时间片它就可以接着运行,当然系
统此时是不想让它运行的,所以不给它CPU时间片。此状态的activity在RAM剩余极少时,
可能被系统杀掉。
Stoped
一个Activity如果被其它activity完全遮盖,那么它就处于Stoped状态。此时它处于“后
台”。此状态的activity也是“活”的,它依然位于内存中,但是窗口管理器中把它除名。
然而,它不再被用户看到并且系统可以在其它组件需要内存时把它杀掉,也就是说它比
paused状态的更容易被杀害。
如果一个activtiy处于paused或stoped状态,系统可以杀死它。杀死它的方法有比较温和
的:请求activity用finish()自杀,或直接用暴力的方法:杀掉activity所在的进程。不论怎
样,activity被从内存中移除。当被杀或自杀的activity重新启动时,它必须被从头创建。
实现生命周期回调
public class ExampleActivity extends Activity {
public voidonCreate(Bundle savedInstanceState) {
// Theactivity is being created.
@Override
t();
}
protected voidonResume() {
// Theactivity has become visible (it is now "resumed").
@Override
e();
}
protected voidonStop() {
// Theactivity is no longer visible (it is now "stopped")
@Override
roy();
}
注意:当你覆写以上函数时,必须首先调用父类的同一方法,就像上例中所示。
这六个方法涵盖了activity的整个生命周期,覆写这些方法们,可以监视activity
生命周期中三种状态的嵌套循环:
l
Activity的可见期位于onStart()和onStop()之间。在可见期内,用户可以看到
activity并与它交互。例如:onStop()在新的activity启动并且当前activity
不在被看到时被调用。在可见期内,你可以在内存中保持与activity显示相关的
资源。例如:你可以在onStart()中注册一个BroadcastReceiver,以监视对界面
有影响的系统事件(比如主题或字体的改变);并其在onStop()中取消注册,因为
此时用户看不到这个activity的界面了。在整个生命周期中,onStart()和onStop()
会被多次调用,因为activity可能多次显示又隐藏,隐藏又显示„
下图展示了这些循环以及在状态切换时activity所经过的步骤。方框表示回调方法。
下表更详细的介绍了生命周期函数的事项。
方法 描述 完成下一个
后可
杀
掉?
onStart() onCreate()
当activity被创建时调用。这是做一般的静态初始化的地否
方,比如创建界面,把数据绑定到列表,等等之类。这个
方法会被传入一个Bundle对像,它包含了activity的上
一次(关闭时)的状态(如果这个状态可以得到)。此方
法后面永远跟着onStart()。
onRestart()
在停止后被调用,但不是停止后马上调用,而是在再次开否
始前调用,也就是在再次调用onStart()之前立即调用。
onStart()
当activity变成可见后立即调用它。如果activity成为最否
上层,则调用onResume(),如果完全被摭盖,就调用
onStop()。
onStart()
onResume()
或onStop()
onPause()
onResume()
or
onStop()
onRestart()
or
onDestroy()
onResume()
当activity处于最上层时,立即调用此方法。此时activity否
获得输入焦点。后面跟着onPause()。
onPause()
当另一个activity要进入Pause状态时调用此方法。这个是
方法一般是用来提交那些发生改变的永久化的数据们,停
止动画和其它消耗CPU的玩意们。这些工作必须以最快
的速度完成,因为在这个方法返回之前,另一个activity
就不能进入resume状态。当它又回到最上层时,后面跟
着onResume(),当它被完全摭盖时,后面跟着onStop()。
onStop()
当activity被完全摭盖时被调用。当activity要销毁时或是
被其它activity完全摭盖时都会发生。如果这个activity
又回到最上层,则后面跟着onRestart(),如果它逝去了,
则跟着onDestroy()。
onDestroy()
在activity销毁之前被调用。这是activity能收到的最后是
一个调用。调用的原因可能是别人在这个activity上调用
了finish(),也可能是系统为了更多的内存空间而把它所
在的进程处死了。在这个方法中,可以调用isFinishing()
来判断自己属于哪一种死法。
nothing
android activity
详解三:保存
activity
的状态
保存activity的状态
在“acitvity的生命周期”一节中提到了当暂停和停止时,activity的状态是被保留在内存中
的,当resume时,它会立即开始执行。
左图表示
acitvity
未销毁,只是被停止再开始的过程,右图表示
acvitiry
所在的进程被关了,
那么
acitvity
就销毁了,然后又被重新创建的过程。
当用户在开启一个新activity时,当前的activity可能在内存中处于停止状态也可能
由于新activity需要更多内存而被系统杀掉了,但不论怎样,当用户在新activity上按返回
键时,他希望看到的是原先的activity的界面。原先的activity如果是被重新创建,那么它
要恢复到用户最后看到它的样子。那么我们怎么做呢?其实也不难,跟据上一节所述,在
onPause()或onStop()或onDestyroy()中保存必要的数据就行了。但是现在google又冒出
一个新的东西:onSaveInstanceState(),观其名可知其意:它是专门用来保存实例状态的,
这个“实例”不是指的activity对象,而是它所在的进程,因为activity的销毁是因为它所
在的进程被杀而造成的。onSaveInstanceState()是在系统感觉需要杀死activity时调用的,
它被传入一个参数:Bundle,这个Bundle可以被认为是个map,字典之类的东西,用”键
-值”来保存数据。
现在又叫人蛋疼了:不是可以在onPause()中保存数据吗?为什么又搞出这样一个家伙来?
它们之间是省木关系呢?原来onSaveInstanceState()的主要目的是保存activity的状态有关
的数据,当系统在杀死activity时,如果它希望activity下次出现的样子跟现在完全一样,
那么它就调用这个onSaveInstanceState(),否则就不调用。所以要明白这一点:
onSaveInstanceState()并不是永远都会调用。比如,当用户在一个activity上按返回时,就
不会调用,因为用户此时明确知道这个activity是要被销毁的,并不期望下次它的样子跟现
在一样(当然开发者可以使它保持临死时的表情,你非要这样做,系统也没办法),所以就
不用调用onSaveInstanceState()。现在应该明白了:在onPause(),onStop()以及onDestroy()
中需要保存的是那些需要永久化是数据,而不是保存用于恢复状态的数据,状态数据有专门
的方法:onSaveInstanceState()。
数据保存在一个Bundle中,Bundle被系统永久化。当再调用activity的onCreate()时,原
先保存的bundle就被传入,以恢复上一次临死时的模样,如果上次死时没有保存Bundle,
则为null。
还没完呢,如果你没有实现自己的onSaveInstanceState(),但是activity上控件的样
子可能依然能被保存并恢复。原来activity类已实现了onSaveInstanceState(),在
onSaveInstanceState()的默认实现中,会调用所有控件的相关方法,把控件们的状态都保
存下来,比如EditText中输入的文字,CheckBox是否被选中等等。然而不是所有的控件都
能被保存,这取决于你是否在layout文件中为控件赋了一个名字(android:id)。有名的就存,
无名的不管。
既然有现成的可用,那么我们到底还要不要自己实现onSaveInstanceState()?这得看
情况了,如果你自己的派生类中有变量影响到UI,或你程序的行为,当然就要把这个变量
也保存了,那么就需要自己实现,否则就不需要,但大多数情况肯定需要自己实现一下下了。
对了,别忘了在你的实现中调用父类的onSaveInstanceState()。
注:由于
onSaveInstanceState()
并不是每次销毁时都会调用,所以不要在其中保存那些需
要永久化的数据,执行保存那些数据的最好地方是:
onPause()
中。
测试你程序的状态恢复能力的最好方法是:旋转屏幕,每当屏幕的方向改变时,当前的
activity就会被系统销毁,然后重新创建(应该是进程被关闭!――不会吧?效率不高哦)。
android activity详解四:保存activity的状态的更多事项
处理系统配置变化
协调activity们
处理系统配置变化
很多设备可以在运行时改变系统配置,比如屏幕方向,键盘布局以及语言等。当类似的
变化发生时,系统会把运行的activity重启(调用onDestroy(),然后调用onStart(),――
哦~,没有调用onRestart()),如果你的activity能跟据这些变化做出相应的处理,那么你
的程序将更稳定可爱。
那么如何应付这些变化呢,最好的办法就是写好状态保存/恢复方法们。比如
onSaveInstanceState(),onRestoreInstanceState()/onCreate()。
对于系统配置改变的详细信息以及基体应对方法,请观“处理运行时配置变化”一节。
协调activity们
当一个activity启动另一个时,两者都在走生命周期。如果这两个activity之间要共享
数据,那么重点要理解当第二个activity被创建时,第一个activity还没有执行到onStop()。
开始新一个和结束前一个之间有交集。
当activityA启动ActivityB时,会按以下顺序执行:
1Activity A 的onPause()执行。
2Activity B的onCreate(),onStart(),onResume()依次执行(此时actvityB具有用户
焦点)。
3Activity A的onStop()被执行(假设A被B完全遮盖)。
你应跟据这个顺序来管理两者之间的数据传递。比如,如果A要向数据库中写入数据,
要保证B在初始化时能读到A写入的完整数据,那么A应在onPause()方法中写入数据,
而不能在onStop()中写入。
2024年8月24日发(作者:韦绢)
android activity
详解一:概述
概述
如何创建Activity
实现用户界面
在名单文件中声明activity
使用intent过虑器
启动一个Activity
启动一个acitvity并得到结果
关闭Activity
概述
Activities 是一个程序的组件之一。它的主要功能是提供界面。
一个程序一般由多个Activity组成,各activities之间关系很松散,它们之间没有
直接的关联。必须有一个activity被指定为主activity,它是程序启动时首先显示的界
面。每个activity都可以随意启动其它的activity。每当一个activity被启动,则前一
个activity就被停止。一个程序中的所有启动的activity都被放在一个栈中,所以被停
止的activity并没有销毁,而在存于棧中。新启动的activity先被存放于栈中,然后获
得输入焦点。在当前活动的activity上点返回键,它被从棧中取出,然后销毁,然后
上一个activity被恢复。
当一个activity因为新的activity启动而被停止时,它会收到状态变化的通知,这
样的变化有多个,每个都会引起系统调用一个相应的回调方法以通知activity,这些
回调方法被统称为“生命周期回调方法”。这些回调方法分别在Activity被创建、停
止、恢复、销毁时被调用。
如何创建Activity
1 从类activity继承。
2 实现“生命周期回调方法”
两个最重要的方法是:
onCreate()--这个是必须实现的函数,在其中做初始化工作。记住:你必须在此
函数中调用setContentView()函数的设置Activity的界面。
onPause()--这个虽然很重要,但不是要必须实现的。此函数在用户离开Activity
时被调用(这一般并不表示Activity要被销毁了)。在这个函数中,你一般需要提交那
些需保存状态的数据(因为用户可能不再返回到这个Activity)。其它回调方法视情况
实现。
实现用户界面
此处的用户界面指的就是activity上的控件们。所有的控件都从View类派生,
所以可以把它们都称为View。每个控件占据一个矩形区域。
控件又分为以下两类:Widgets是完成特定功能的控件,比如button,text
field,checkbox 等。Layouts是容纳Widgets控件并进行排版的控件,当然,Layout
中还可以容纳Layout。Widgets从View类派生,Layouts从ViewGroup类中派生,
开发者可以从View或ViewGroup派生创造自己的控件。
定义界面的最好的方法是使用XML格式的layout文件,它作为资源保存在工程
中,可以在工程的res/layout下面找到这些XML文件。通过这种方式就做到了代码
与界分离。把layout 下的某个XML设置为某个Activity的界面,需调用Activity的
setContentView(),把XML的资源ID作为参数传入即可。
在名单文件中声明activity
为了能让系统操作你的Activity,你必须在工程的名单文件中声明它。例如:
...
...
当然有很多属性可以设置给Activity,比如label,icon或主题等等。详情请查看
注意看
最前面有个”.”,如果你把它忘了,程序运行就会出错,而你很难找出错误的原因。
其次,不论你是Activity是只内部使用还是外部使用,都要去名单文件中注册,否则
依然会出现莫名其妙的错误,只是在内部使用时,不需要为acitivity增加意图过滤器。
使用intent过虑器
可以为一个
过虑器的目的是告诉其它组件如何启动这个Activity。当你使用ADT创建一个新工程
时,根Activity被自动创建,它已具有两个意图过虑器,一个意图过虑器声明这个
Activity负责响应“main”action;另一个过虑器声明这个Activity须被置
于”launcher”类别之下。一般是这个样子:
如果你写的程序中的Activity不需被其它程序调用,那么不需为这个Activity增
加任何意图过滤器。但程序中必须有一个Activity被指定为”main” Action
和”launcher” category。你自己程中的 Activity可以用更直接的方式调用。
然而,如果你想让你的Activity被其它程序调用,那么你需要为它增加意图过滤
器。这些过意图滤器包括
activity响应何种类型的intent。
启动一个Activity
你可以用startActivity()启动一个activity,它有一个参数是intent,你需要在这个
intent中指明要调用的activity。Intent中你可以明确地指定要启动的activity,或只指
定activity的类型,此时系统会为你挑选一个合适的activity,这个activity可能位于
其它程序中,也可能位于你自己的程序中。Intent中可以带一坨被新activity使用的
数据(相当于参数传递)。
在你的程序内部,如果需要启动一个内部的activity,你需在intent中明确指定
新activity的类名。例如:
Intent intent = new Intent(this, );
startActivity(intent);
SignInActivity是要启动的activity类。
然而,你的程序可能想执行自身没有提供的功能,比如发出邮件,发送短信息等。
此时,需要启动其它程序提供的activity。此时就体现出intent的真正价值来了:它
可以很容易地启动其它程序提供的activity,你只需要在intent中指定你要执行的动
作,然后调用 startActivity() ,系统就会跟据你的需要,为你选择一个合适的activity,
并启动它。如果同时有多个activity可以执行这动作,那么用户可以选择哪个被使用。
例如,你想让用户发送一个电子邮件,你可以创建以下的Intent:
Intent intent = new Intent(_SEND);
ra(_EMAIL, recipientArray);
startActivity(intent);
putExtra()是设置扩充数据的,.EXTRA_EMAIL表明第二个参数recipientArray
里面放的是多个email地址。当发邮件的程序被启动并接收到这个intent时,它就把
邮件地址们放到它的Acitivity界面的“to”控件中。当用户发送完毕返回时,你的
activity就恢复运行(resume)。可以看到,启动另外一个程序是多么的容易。
启动一个acitvity并得到结果
有时,你可能想从你启动的activity获得其执行后返回的结果。此时你可以用方
法startActivityForResult()来启动新acitivity(不再是startActivity了)。然后,你的程
序还需要定义回调方法onActivityResult()。当新activity运行结束时,它把一个intent
返回给你的程序,这个intent是在onActivityResult()中被接收。
例如:你想让用户打开通讯录,从中选择一个联系人,然后你取得用户所选的联
系人,对之进行处理。以下是示例代码:
private void pickContact() {
//Create anintent to "pick" a contact, as defined by the content provider URI
Intent intent =new Intent(_PICK, T_URI);
startActivityForResult(intent, PICK_CONTACT_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, intresultCode, Intent data) {
// If the requestwent well (OK) and the request was
PICK_CONTACT_REQUEST
if (resultCode== _OK && requestCode ==
PICK_CONTACT_REQUEST) {
// Perform aquery to the contact's content provider for the contact's name
Cursorcursor = getContentResolver().query(a(),new
String[]{Y_NAME}, null, null, null);
if(First()) { // True if the cursor is not empty
intcolumnIndex =
umnIndex(Y_NAME);
String name =ing(columnIndex);
// Dosomething with the selected contact'
}
}
}
此例子展示了在onActivityResult()中的基本逻辑流程。首选检查所启动的
Activity是否正确运行,resultCode为_OK表示正常,其次,查看
requestCode是否与当时请求的一致,即是否为PICK_CONTACT_REQUEST。都
通过后,开始操作返回的数据,也就是data参数。
Data是这样处理的,用ContentResolver向内容提供者发出请求,这个请求会
返回一个游标,通过这个游标读取数据,这很像数据库表的操作。要理解此处,请查
阅Content Providers一节。
关闭Activity
Activity可以内部调用finish()方法关闭它自己,也可以调用finishActivity()方法关
闭其它的activity。
注意:大多数情况下,你不应主动结束一个activity。系统掌管着activity的生命,
所以你也不必结束自己的activity。使用上述方法会破坏用户体验。除非你觉得很必
要时,否则就不要做!
android activity
详解二:
Activity
的生命周期
管理Activity的生命周期
实现生命周期回调
管理Activity的生命周期
通过实现activity的生命周期回调方法来管理你的activity,是创造既稳定又灵活的
activity的关键。Activity的生命周期直接受到相关的其它activity和它的任务以及所在栈的
影响。
一个activity可生存在三种基本的状态中:
Resumed
Activity位于屏幕的最上层,并具有用户焦点,用户可以操作它。(此状态有时也被认为
是“运行”状态)。
Paused
Activity B位于最上层并其获得输入焦点,acitvity A位于其下一层,但activity A依然可
见,此时activity A就处于Paused状态。Activity A可见的原因可能是activity B是半透明
的,或acitvity B不覆盖整个屏幕。此状态的activity依然是“活”的,因为它还是位于内
存中,并且它被窗口管理器所管理。它只要获取到CPU时间片它就可以接着运行,当然系
统此时是不想让它运行的,所以不给它CPU时间片。此状态的activity在RAM剩余极少时,
可能被系统杀掉。
Stoped
一个Activity如果被其它activity完全遮盖,那么它就处于Stoped状态。此时它处于“后
台”。此状态的activity也是“活”的,它依然位于内存中,但是窗口管理器中把它除名。
然而,它不再被用户看到并且系统可以在其它组件需要内存时把它杀掉,也就是说它比
paused状态的更容易被杀害。
如果一个activtiy处于paused或stoped状态,系统可以杀死它。杀死它的方法有比较温和
的:请求activity用finish()自杀,或直接用暴力的方法:杀掉activity所在的进程。不论怎
样,activity被从内存中移除。当被杀或自杀的activity重新启动时,它必须被从头创建。
实现生命周期回调
public class ExampleActivity extends Activity {
public voidonCreate(Bundle savedInstanceState) {
// Theactivity is being created.
@Override
t();
}
protected voidonResume() {
// Theactivity has become visible (it is now "resumed").
@Override
e();
}
protected voidonStop() {
// Theactivity is no longer visible (it is now "stopped")
@Override
roy();
}
注意:当你覆写以上函数时,必须首先调用父类的同一方法,就像上例中所示。
这六个方法涵盖了activity的整个生命周期,覆写这些方法们,可以监视activity
生命周期中三种状态的嵌套循环:
l
Activity的可见期位于onStart()和onStop()之间。在可见期内,用户可以看到
activity并与它交互。例如:onStop()在新的activity启动并且当前activity
不在被看到时被调用。在可见期内,你可以在内存中保持与activity显示相关的
资源。例如:你可以在onStart()中注册一个BroadcastReceiver,以监视对界面
有影响的系统事件(比如主题或字体的改变);并其在onStop()中取消注册,因为
此时用户看不到这个activity的界面了。在整个生命周期中,onStart()和onStop()
会被多次调用,因为activity可能多次显示又隐藏,隐藏又显示„
下图展示了这些循环以及在状态切换时activity所经过的步骤。方框表示回调方法。
下表更详细的介绍了生命周期函数的事项。
方法 描述 完成下一个
后可
杀
掉?
onStart() onCreate()
当activity被创建时调用。这是做一般的静态初始化的地否
方,比如创建界面,把数据绑定到列表,等等之类。这个
方法会被传入一个Bundle对像,它包含了activity的上
一次(关闭时)的状态(如果这个状态可以得到)。此方
法后面永远跟着onStart()。
onRestart()
在停止后被调用,但不是停止后马上调用,而是在再次开否
始前调用,也就是在再次调用onStart()之前立即调用。
onStart()
当activity变成可见后立即调用它。如果activity成为最否
上层,则调用onResume(),如果完全被摭盖,就调用
onStop()。
onStart()
onResume()
或onStop()
onPause()
onResume()
or
onStop()
onRestart()
or
onDestroy()
onResume()
当activity处于最上层时,立即调用此方法。此时activity否
获得输入焦点。后面跟着onPause()。
onPause()
当另一个activity要进入Pause状态时调用此方法。这个是
方法一般是用来提交那些发生改变的永久化的数据们,停
止动画和其它消耗CPU的玩意们。这些工作必须以最快
的速度完成,因为在这个方法返回之前,另一个activity
就不能进入resume状态。当它又回到最上层时,后面跟
着onResume(),当它被完全摭盖时,后面跟着onStop()。
onStop()
当activity被完全摭盖时被调用。当activity要销毁时或是
被其它activity完全摭盖时都会发生。如果这个activity
又回到最上层,则后面跟着onRestart(),如果它逝去了,
则跟着onDestroy()。
onDestroy()
在activity销毁之前被调用。这是activity能收到的最后是
一个调用。调用的原因可能是别人在这个activity上调用
了finish(),也可能是系统为了更多的内存空间而把它所
在的进程处死了。在这个方法中,可以调用isFinishing()
来判断自己属于哪一种死法。
nothing
android activity
详解三:保存
activity
的状态
保存activity的状态
在“acitvity的生命周期”一节中提到了当暂停和停止时,activity的状态是被保留在内存中
的,当resume时,它会立即开始执行。
左图表示
acitvity
未销毁,只是被停止再开始的过程,右图表示
acvitiry
所在的进程被关了,
那么
acitvity
就销毁了,然后又被重新创建的过程。
当用户在开启一个新activity时,当前的activity可能在内存中处于停止状态也可能
由于新activity需要更多内存而被系统杀掉了,但不论怎样,当用户在新activity上按返回
键时,他希望看到的是原先的activity的界面。原先的activity如果是被重新创建,那么它
要恢复到用户最后看到它的样子。那么我们怎么做呢?其实也不难,跟据上一节所述,在
onPause()或onStop()或onDestyroy()中保存必要的数据就行了。但是现在google又冒出
一个新的东西:onSaveInstanceState(),观其名可知其意:它是专门用来保存实例状态的,
这个“实例”不是指的activity对象,而是它所在的进程,因为activity的销毁是因为它所
在的进程被杀而造成的。onSaveInstanceState()是在系统感觉需要杀死activity时调用的,
它被传入一个参数:Bundle,这个Bundle可以被认为是个map,字典之类的东西,用”键
-值”来保存数据。
现在又叫人蛋疼了:不是可以在onPause()中保存数据吗?为什么又搞出这样一个家伙来?
它们之间是省木关系呢?原来onSaveInstanceState()的主要目的是保存activity的状态有关
的数据,当系统在杀死activity时,如果它希望activity下次出现的样子跟现在完全一样,
那么它就调用这个onSaveInstanceState(),否则就不调用。所以要明白这一点:
onSaveInstanceState()并不是永远都会调用。比如,当用户在一个activity上按返回时,就
不会调用,因为用户此时明确知道这个activity是要被销毁的,并不期望下次它的样子跟现
在一样(当然开发者可以使它保持临死时的表情,你非要这样做,系统也没办法),所以就
不用调用onSaveInstanceState()。现在应该明白了:在onPause(),onStop()以及onDestroy()
中需要保存的是那些需要永久化是数据,而不是保存用于恢复状态的数据,状态数据有专门
的方法:onSaveInstanceState()。
数据保存在一个Bundle中,Bundle被系统永久化。当再调用activity的onCreate()时,原
先保存的bundle就被传入,以恢复上一次临死时的模样,如果上次死时没有保存Bundle,
则为null。
还没完呢,如果你没有实现自己的onSaveInstanceState(),但是activity上控件的样
子可能依然能被保存并恢复。原来activity类已实现了onSaveInstanceState(),在
onSaveInstanceState()的默认实现中,会调用所有控件的相关方法,把控件们的状态都保
存下来,比如EditText中输入的文字,CheckBox是否被选中等等。然而不是所有的控件都
能被保存,这取决于你是否在layout文件中为控件赋了一个名字(android:id)。有名的就存,
无名的不管。
既然有现成的可用,那么我们到底还要不要自己实现onSaveInstanceState()?这得看
情况了,如果你自己的派生类中有变量影响到UI,或你程序的行为,当然就要把这个变量
也保存了,那么就需要自己实现,否则就不需要,但大多数情况肯定需要自己实现一下下了。
对了,别忘了在你的实现中调用父类的onSaveInstanceState()。
注:由于
onSaveInstanceState()
并不是每次销毁时都会调用,所以不要在其中保存那些需
要永久化的数据,执行保存那些数据的最好地方是:
onPause()
中。
测试你程序的状态恢复能力的最好方法是:旋转屏幕,每当屏幕的方向改变时,当前的
activity就会被系统销毁,然后重新创建(应该是进程被关闭!――不会吧?效率不高哦)。
android activity详解四:保存activity的状态的更多事项
处理系统配置变化
协调activity们
处理系统配置变化
很多设备可以在运行时改变系统配置,比如屏幕方向,键盘布局以及语言等。当类似的
变化发生时,系统会把运行的activity重启(调用onDestroy(),然后调用onStart(),――
哦~,没有调用onRestart()),如果你的activity能跟据这些变化做出相应的处理,那么你
的程序将更稳定可爱。
那么如何应付这些变化呢,最好的办法就是写好状态保存/恢复方法们。比如
onSaveInstanceState(),onRestoreInstanceState()/onCreate()。
对于系统配置改变的详细信息以及基体应对方法,请观“处理运行时配置变化”一节。
协调activity们
当一个activity启动另一个时,两者都在走生命周期。如果这两个activity之间要共享
数据,那么重点要理解当第二个activity被创建时,第一个activity还没有执行到onStop()。
开始新一个和结束前一个之间有交集。
当activityA启动ActivityB时,会按以下顺序执行:
1Activity A 的onPause()执行。
2Activity B的onCreate(),onStart(),onResume()依次执行(此时actvityB具有用户
焦点)。
3Activity A的onStop()被执行(假设A被B完全遮盖)。
你应跟据这个顺序来管理两者之间的数据传递。比如,如果A要向数据库中写入数据,
要保证B在初始化时能读到A写入的完整数据,那么A应在onPause()方法中写入数据,
而不能在onStop()中写入。