自己最近每天早上学点Rxjava,网络请求,然后下午就开始《Android艺术探究》这本书的阅读,抽空继续看下计算机网络,晚上就是写项目的时候。加油,还是要坚持减肥运动,不想当死肥宅了。
我记得我刚开始学安卓的时候,就是觉得活动就是一个界面,类似一个剧场一样,每个剧场都要先设计好他的布置场景(就是界面xml),处理好剧场里面的各种事情(点击啊,触发啊)。还有和其他剧场之间的跳转。当时学的时候,就简单学个皮毛,其实里面各种情况自己重来也没考虑过,就只是会简单的活动跳转,现在重新再好好看下,然后去看下源码。
其实自己还是对活动一知半解,还是好好耐下心来学。
活动的生命周期有两个部分,一种是典型情况下的生命周期,另一种是异常情况下的生命周期。典型情况下,就是指用户在参与的过程中,activity的生命周期的改变;异常情况下生命周期是指Activity在被系统回收或者当前设备的布局改变,导致Activity被销毁重建。
一般情况下,activity会经历如下的生命周期
(1)onCreat
表示:活动正在创建中
作用:做一些初始化的工作,加载界面布局资源,初始化活动所需的数据
备注:无
(2)onRestart
表示:活动正在重新启动
作用:重新启动活动
备注:当当前活动从不可见到可见的状态时候,这个被调用
(3)onStart
表示:活动正在被启动,即将开始
作用:活动已经显示出来了,但是我们还是看不见
备注:这个时候活动已经可见了,但没出现在前台,无法和用户交互
(4)onResume
表示:活动已经可见了
作用:并在前台做交互
备注:无
(5)onPause
表示:活动正在停止
作用:正常情况下紧接着onstop,果立刻返回当前Activity,那么onResume会被调用(情景几乎不可能)。可以做数据存储、停止动画。不能做耗时操作,因为onPause执行完,新的Activity才能onResume,会影响新的Activity的显示
备注:无
(6)onStop
表示:活动即将停止
作用:稍微重量级的回收工作
备注:不能太耗时
(7)onDestroy
表示:活动即将被销毁
作用:回收工作和最终的资源释放
备注:无
两种情况
1资源相关的系统配置发生改变导致的Activity被杀死并重新创建
2资源不足导致的优先级低的Activity被杀死
有两个重要的方法onSaveInstanceState和onRestoreInstanceStart
情景模式:
在默认情况下,如果我们的activity不做处理的话,当系统配置发生改变的时候,activity就会销毁并且重建,因为他们是在异常情况下的,所以会有个恢复机制
当系统配置改变之后,activity就被销毁,然后onPause,onStop,onDestroy均被调用,同时异常情况下的时候,系统会调用onSaveInstanceState保存当前的Activity的状态,然后在activity重新建立之后,系统会调用onRestoreInstanceStart方法,并把activity销毁的时候,nSaveInstanceState方法保存的Bundle对象作为参数,传递给onRestoreInstanceStart方法
就一句话,异常情况下活动被干掉
调用的时候在onStop之前,和onPause没有特点的时间关系
- 当用户按下HOME键时。
- 长按HOME键,选择运行其他的程序时。
- 下电源按键(关闭屏幕显示)时
- 从activity A中启动一个新的activity时
- 屏幕方向切换时,例如从竖屏切换到横屏时
在屏幕切换之前,系统会销毁activity A,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState()一定会被执行,且也一定会执行onRestoreInstanceState()。
onRestoreInstanceState()被调用的前提是,原activity “确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity ,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行 此也说明上二者,大多数情况下不成对被使用。
onRestoreInstanceState()在onStart() 和 onPostCreate(Bundle)之间调用。
当Activity在异常情况下的时候,重新建立的时候,系统会默认保存当前activity的视图,并在重启的时候为我们恢复这些数据并在重建后恢复这些数据,比如EditText中输入的文本、ListView滚动到的位置,具体保存的内容需要看具体View的onSaveInstanceState()和onRestoreInstanceState()实现。
先看下安卓里面活动的优先级
当系统内存不足的情况下,系统就会按照上面的优先级顺序去杀死Activity的进程,并通过
onSaveInstanceState和onRestoreInstanceStart来存储和恢复这些数据,如果一个进程没有四大组件在执行,很快就被系统杀死了。最好的方法就是将后台工作放到Service中,从而保证有一定的优先级
在安卓活动中,每次都是创建一个活动时候,然后实例化并把他加入任务栈,然后按back键,就会发现这些Activity就会一一回退,但是每次多次启动这个活动的时候,又要重新建一次,就很耗时,所以安卓系统提供了四种启动模式
stangdard
这个是标准的模式,也是系统默认的模式
singleTop
这个是栈顶复用的模式
singleInstance
单实例模式,是singleTask模式的增强,具有singleTask模式的所有特性。除此之外还有一个特点就是此模式的Activity只能单独的位于一个任务栈中
备注singleInstance之一坑
此时有3个Activity,A,B,C,然后除了活动B的启动模式是singlelnstance,其余的都是默认的,然后tartActivity了一个ActivityA,在ActivityA里startActivity了一个ActivityB,在ActivityB里startActivity了一个ActivityC。此时在当前的任务栈中的顺序是,ActivityA->ActivityB->ActivityC。
理来说在当前ActivityC页面按返回键,finish当前界面后应当回到ActivityB界面。但是事与愿违,奇迹出现了,页面直接回到了ActivityA
ActivityB则是存在另个栈中。所以当关闭了ActivityC的时候,它自然就会去找当前任务栈存在的activity。当前的activity都关闭了之后,才会去找另一个任务栈中的activity
这个坑很有意思,总结下就是
备注singleInstance之二坑
此时有两个个activity,ActivityA,ActivityB,ActivityA的启动模式为默认的,ActivityB的启动模式为singleInstance。当在ActivityA里startActivity了ActivityB,当前页面为ActivityB。按下home键。应用退到后台。此时再点击图标进入APP,按照天理来说,此时的界面应该是ActivityB,可是奇迹又出现了,当前显示的界面是ActivityA。
这是因为当重新启动的时候,系统会先去找主栈(我是这么叫的)里的activity,也就是APP中LAUNCHER的activity所处在的栈。查看是否有存在的activity。没有的话则会重新启动LAUNCHER。
要解决这个方法则是和一坑的解决办法一样,在ActivityB定义一个全局变量,public static boolean returnActivityB;在oncreat方法将returnActivityB=true;然后在ActivityA界面onstart方法里判断returnActivityB是否为true,是的话就跳转到ActivityB,同时将returnActivityB=false;这样就能解决跳转的问题了。
任务是一个Activity的集合,它使用栈的方式来管理其中的Activity,这个栈又被称为返回栈(back stack),栈中Activity的顺序就是按照它们被打开的顺序依次存放的,栈中Activity的顺序就是按照它们被打开的顺序依次存放的。
如何用户将任务切换到后台之后过了很长一段时间,系统会将这个任务中除了最底层的那个Activity之外的其它所有Activity全部清除掉。当用户重新回到这个任务的时候,最底层的那个Activity将得到恢复。这个是系统默认的行为,因为既然过了这么长的一段时间,用户很有可能早就忘记了当时正在做什么,那么重新回到这个任务的时候,基本上应该是要去做点新的事情了
在元素中设置以下几种属性就可以改变系统这一默认行为:
alwaysRetainTaskState
如果将最底层的那个Activity的这个属性设置为true,那么上面所描述的默认行为就将不会发生,任务中所有的Activity即使过了很长一段时间之后仍然会被继续保留。
clearTaskOnLaunch
如果将最底层的那个Activity的这个属性设置为true,那么只要用户离开了当前任务,再次返回的时候就会将最底层Activity之上的所有其它Activity全部清除掉。简单来讲,就是一种和alwaysRetainTaskState完全相反的工作模式,它保证每次返回任务的时候都会是一种初始化状态,即使用户仅仅离开了很短的一段时间。
finishOnTaskLaunch
这个属性和clearTaskOnLaunch是比较类似的,不过它不是作用于整个任务上的,而是作用于单个Activity上。如果某个Activity将这个属性设置成true,那么用户一旦离开了当前任务,再次返回时这个Activity就会被清除掉。
TaskAffinity翻译为任务相关性,标识了一个Activity所需的任务栈的名字
allowTaskReparenting主要作用是Activity的迁移,从与taskAffinity属性不同的任务栈迁移到与其相同名称的任务栈,且只有在resettask时才会生效,从桌面启动App会带FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,在reset task时会根据allowTaskReparenting的值迁移Activity。
两种方式
1.在AndroidMenifest中指定
<activity android:name=".SingleTaskActivity"
android:launchMode="singleTask"/>
2.通过Intent中设置标志位来指定
Intent intent = new Intent(MainActivity.this, SingleTaskActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
注意点:
Intent中的Flags很多,官方文档内有详细介绍。下面介绍一部分比较常用的Flag。
FLAG_ACTIVITY_NEW_TASK
官方文档介绍说,这个标志对应这singleTask模式,但是经过实践,并不是如此。
FLAG_ACTIVITY_SINGLE_TOP
对应着singleTop启动模式,经实践,二者是一样的
FLAG_ACTIVITY_CLEAR_TOP
如果设置了此标志位,并且被启动的Activity已经存在于这个Task中,则不会启动一个该Activity的新的实例,而是弹出在Task中,该Activity上的所有Activity。同时,这个intent作为一个新的intent会传递给该Activity。
例如task中有A B C D。如果D使用附带此Flag的intent去启动B,则C,D会出栈,B收到新的intent。
现在在栈顶运行的B实例要么通过调用onNewIntent()接受到新的intent,要么会自我销毁,在通过此intent重建。如果你设置了启动模式为“multiple”(默认的)并且没有设置“FLAG_ACTIVITY_SINGLE_TOP”,则B实例会销毁重启;否则其他所有情况,都是在onNewIntent()中处理该Intent。
这个启动模式和FLAG_ACTIVITY_NEW_TASK在一起使用时有很好的效果:如果用来启动一个task的root Activity,将把所有的这个栈中运行的实例均带到前台,然后全部清空到root状态。
FLAG_ACTIVITY_CLEAR_TASK
如果设置了这个标志的intent通过Context.startActivity()去启动某个Activity,那么该标志会导致任何与此获得弄个相关联的task被清空,在这个活动启动之前。然后,该活动就会变成根Activity,之前的活动全被销毁了。这个标志只能和FLAG_ACTIVITY_NEW_TASK在一起使用
启动Activity的方式分为两种,显示调用和隐式调用。
显示调用需要指定启动对象的组件信息,包括包名和类名。隐式调用需要Intent能够匹配目标组件的IntentFilter中所设置的过滤信息,如果匹配失败则无法启动。
简单的隐试启动的例子
先在声明下
<activity android:name=".Main2Activity">
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START"/>
<category android:name="android.intent.category.DEFAULT"/>
intent-filter>
activity>
然后启动的时候
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.activitytest.ACTION_START");
startActivity(intent);
}
});
匹配成功,然后就启动活动二了
在隐式调用的时候需要Intent能够匹配目标组建的IntentFilter中所设置的过滤信息,如果不匹配将无法启动Activity,IntentFilter中所过滤的信息有action,category,data
action是一个字符串,系统预定义了一些action,同时我们自己的应用里也可以定义自己的action。
匹配action,总结来说action必须存在且必须和过滤中的其中一个action相同。
category是一个字符串,系统预定义了一些category,同时我们自己的应用里也可以定义自己的category。
data格式
"aa"
android:host="aa"
android:port="aa"
android:path="aa"
android:pathPrefix="aa"
android:mimeType="aa"/>
data由两部分组成,mimeType和URI。mimeType是媒体类型,比如image/jpeg、audio/mpeg4-generic和video/*,表示不同的媒体格式。URI的结构如下:
:// :/ [||]
比如:
content://com.example.project:200/folder/subfolder/etc
http://www.baidu.com:80/search/info
匹配规则:
如果找不到能够匹配成功的Activity就会报错,所以可以在隐式调用之前做一个判断。
哇哇哇,看完一章花了这么多时间哇哇哇,真的是刚开始学的时候,自己没有好好认真的看,现在才在补,加油,不会就去查,去问,然后总结
参考资料《安卓艺术探究》+各种人的博客