1_Activity的生命周期和启动模式

Activity的生命周期和启动模式

1、Activity的生命周期解析

所谓的典型情况下的生命周期,是指用户参与的情况下,Activity所经过的生命周期的改变;而异常情况下的生命周期是指Activity被系统回收或者由于当前设备的Configuration发生改变从而导致Activity被销毁重建。

1.1、典型情况下

1)、针对一个特定的Activity,第一次启动,回调如下:onCreate()--->onStart()---->onResume()

2)、当用户 打开新的Activity或者切换到桌面时,回调如下:onPause()-->onStop(),特殊情况,如果新的Activity采用了透明的主题,那么当前Activity不会回调onStop

3)、当用户再次回到原Activity时,回调如下:onRestart()--->onStart()--->onResume()

4)、当用户按back键回退时,回调如下:onPause()--->onStop()--->onDestory()

问题:

1、onStart和onResume、onPause和onStop从描述上来看差不多,对我们来说有什么实质性的区别?

onStart和onStop是从Activity是否可见这个角度来回调的;onResume和onPause是从Activity是否位于前台这个角度来回调的,除了这种区别,在应用中并没有其他明显区别。

2、假设当前的Activity为A,如果这时用户打开一个新Activity B,那么B的onResume和A的onPause哪个先执行?

调用顺序为:A onPause()---->B onCreate()---->B onStart()---->B onResume()---->A onStop();因此,onPause和onStop都不能做耗时操作,尤其是onPause,这也意味着,我们应该尽量在onStop中做操作,从而使得新的Activity尽快显示出来并切换到前台。避免出现页面切换时的卡顿现象。

1.2、异常情况下

1)、资源相关的系统配置发生改变导致Activity被杀死并重新创建

在默认情况下,如果我们的Activity不做任何特殊处理,那么系统配置发生改变后,Activity就会销毁并重新创建。

当系统配置发生改变后,Activity会被销毁,其onPause、onStop、onDestroy均会被调用,同时由于Activity是在异常情况下终止的,系统会调用onSaveInstanceState来保存当前Activity的状态。调用时机是在onStop之前,它和onPause没有既定的时序关系。

当Activity被重新创建后,系统会调用onRestoreInstanceState,并且把Activity销毁时onSaveInstanceState方法说保存的Bundle对象作为参数传给onRestoreInstanceState和onCreate方法。

当Activity在异常情况下需要重新创建时,系统会默认为我们保存当前Activity的视图结构,并且在Activity重启后为我们恢复这些数据。

2)、内存不足导致低优先级的Activity被杀死

Activity按照优先级从高到低,可以分为三种:

1)、前台Activity--正在和用户交互的Activity,优先级最高

2)、可见但非前台Activity--比如Activity中弹出一个对话框,导致Activity可见但无法与用户直接交互

3)、后台Activity--已经被暂停的Activity,不可见,优先级最低

如果一个进程中没有四大组件在执行,那么这个进程将很快被系统杀死。因此,一些后台工作不适合脱离四大组件而独立运行在后台中,把后台工作放入Service中,从而保证进程有一定的优先级,这样不会轻易被系统杀死。

如果我们不想系统重新创建Activity,那么可以给Activity指定configChanges属性。比如不想让Activity在屏幕旋转时重新创建就可以给configChanges属性添加orientation这个值。

<span style="white-space:pre">	</span>android:configChanges="orientation"
配置了以上属性,系统就不会在对应变化时重新创建,而是调用Activity的onConfigurationChanged方法。

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

 2、Activity的启动模式

2.1、Activity的LaunchMode

Activity的启动模式有四种,分别为:

1)、standard:标准模式,这也是系统的默认模式。每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否存在。

standard模式的Activity默认会进入启动它的Activity所属的任务栈中,对于非Activity类型的Context(如ApplicationContext),并没有任务栈,启动Activity时需要加上

FLAG_ACTIVITY_NEW_TASK标记位,这样启动时就会为它创建一个新的任务栈。

2)、singleTop:栈顶复用模式,如果行Activity已经位于任务栈的栈顶,那么此Activity不会被创建,同时它的onNewIntent方法会被回调,通过此方法的参数我们可以取出当前请求的信息。如果新的Activity实例已存在但不是位于栈顶,那么新Activity仍然会重建。

3)、singleTask:栈内复用模式,栈内单例模式,在这种情况下,只要新Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,和SingleTop模式一样,系统也会回调onNewIntent。并且把新Activity移到栈顶,去除新Activity上面的其他Activity。

4)、singleInstance:单实例模式,这是一种加强的singleTask模式,它具有singleTask模式的所有特性,此种模式的Activity只能单独地位于一个任务栈中。

taskAffinity:任务相关性,它标识一个Activity说需要的任务栈的名字,默认情况下,所有Activity所需的任务栈的名字为应用的包名,taskAffinity属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有意义。

当taskAffinity和singleTask启动模式配对使用时,它是具有该模式的Activity的目前任务栈的名字,待启动的Activity会运行在名字和taskAffinity相同的任务栈中。

当taskAffinity和allowTaskReparenting结合时,这种情况比较复杂,会产生特殊的效果。当一个应用A启动了应用B的某个Activity,如果这个Activity的allowTaskReparenting属性为true的话,那么当应用B被启动后,此Activity会直接从应用A的任务栈转移到应用B的任务栈中。

给Activity指定启动模式的两种方式:

1)、通过AndroidMenifest为Activity指定启动模式

2)、通过Intent标识位来为Activity指定启动模式

区别:优先级上第二种方式高于第一种方式,当两种同时存在时,以第二种为准;

第一种方式无法直接为Activity设定FLAG_ACTIVITY_CLEAR_TOP标识,而第二种方式无法为Activity指定singleInstance模式

2.2、Activity的Flags

1)、FLAG_ACTIVITY_NEW_TASK:这个标识位的作用是为Activity指定“singleTask”启动模式,其效果和在xml中指定该启动模式相同

2)、FLAG_ACTIVITY_SINGLE_TOP:这个标识位的作用是为Activity指定“singleTop”启动模式,其效果和在XML中指定该启动模式相同

3)、FLAG_ACTIVITY_CLEAR_TOP:具有此标识位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。这个标志位一般和singleTask启动模式一起出现,在这种情况下,被启动Activity的实例如果已经存在,那么系统就会调用它的onNewIntent。如果被启动的Activity采用standard模式启动,那么它连同它之上的Activity都要出栈,系统会创建新的Activity实例并放入栈顶。

4)、FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有这个标志位的Activity不会出现在历史Activity的列表中,当某些情况下我们不希望用户通过历史列表回到我们的Activity时这个标志比较有用。它等同于在XML中指定Activity属性android:excludeFromRecents="true";

3、IntentFilter的匹配规则

启动一个Activity分为显示调用和隐式调用

隐式调用需要Intent能够匹配目标组件的IntentFilter中所设置的过滤信息,如果不匹配将无法启动目标Activity。IntentFilter中的过滤信息有action、category、data。为了匹配过滤列表,需要同时匹配过滤列表中的action、category、data信息,否则匹配失败。

只有一个Intent同时匹配action类别、category类别、data类别才算完全匹配。只有完全匹配才能成功匹配目标Activity。一个Activity中可以有多个intent-filter,一个intent只要能匹配任何一组intent-filter即可成功启动对应的Activity。

1)、action匹配规则

action是一个字符串,系统预定义了一些action,同时我们也可以在应用中定义自己的action。action的匹配规则是Intent中的action必须能够和过滤规则中的action匹配,这里说的匹配是指action的字符串值完全一样。一个过滤规则中可以有多个action,那么只要Intent中的action能够和过滤规则中的任何一个action相同即可匹配成功

2)category匹配规则

category是一个字符串,系统预定义了一些category,同时我们也可以在应用中定义自己的category。Intent中如果出现了category,不管有几个category,对于每个category来说,它必须是过滤规则中的定义的category。

category和action匹配过程不同,action是要求Intent中必须有一个action且必须能够和过滤规则中的某个action;而category要求Intent可以没有category,但如果一旦有category,不管有几个,每个都要能够和过滤规则中的任何一个category相同。

为什么不设置category也可以匹配呢?原因是系统在调用startActivity或者startActivityForResult时会默认为Intent加上“android.intent.category.DEFAULT”这个category。

为了我们的Activity能够接收隐式调用,就必须在intent-filter中指定“android.intent.category.DEFAULT”这个category,这样intent中默认不添加category也不会报错。

3)、data匹配规则

data的匹配规则和action类似,如果Intent-filter中定义了data,那么intent中必须也要定义可匹配的data。

data又两部分组成,mimeType和URI。mimeType指媒体类型,比如image/jpeg、audio/mpeg4-generic和video/*等,可以表示图片、文本、视频等不同的媒体格式,而URI中包含的数据就比较多了

  <scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern]
Scheme:URI模式,比如:http、file、content等,必须指定Scheme。

Host:URI的主机名,比如:www.baidu.com,必须制定host。

Port:URI中的端口号,比如80,仅当URI中指定了scheme和host参数时port参数才是有意义的。

Path、pathPattern和pathPrefix:这三个参数表述路径信息。

如下过滤规则

 <span style="white-space:pre">	</span><intent-filter>
                <data android:mimeType="image/*" />
                ...
        </intent-filter>
这种规则指定了媒体类型为所有类型的图片,那么Intent中的mimeType属性必须为“image/*”才能匹配,这种情况下虽然过滤规则没有指定URI,但有默认值,URI默认为content和file。也就是说,虽然没有指定URI,但是Intent中的URI部分的scheme必须为content或者file才能匹配,这点需要尤其注意的。

    intent.setDataAndType(Uri.parse("file://adb"),"image/png");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值