Android四大组件之Activity

0.写在前面的话

本篇文章最初找工作时期准备面试时看《Android开发艺术探索》一书的总结的笔记,好记性不如烂键盘,再综合一些网上关于Activity必知必会的知识点加以总结。不断更新中……

1.Activity的生命周期

1.1 生命周期图:

(1) onCreate():当 Activity 第一次创建时会被调用。

(2) onRestart():表示Activity正在重新启动。一般情况下,当当前Activity从不可见重新变为可见状态时,onRestart就会被调用。这种情形一般是用户行为导致的,比如用户按Home键切换到桌面或打开了另一个新的Activity,接着用户又回到了这个Actvity。

(3) onStart(): 表示Activity正在被启动,即将开始,这时Activity已经出现了,但是还没有出现在前台,无法与用户交互。这个时候可以理解为Activity已经显示出来,但是我们还看不到。

(4) onResume():表示Activity已经可见了,并且出现在前台并开始活动。需要和onStart()对比,onStart的时候Activity还在后台,onResume的时候Activity才显示到前台。

(5) onPause():表示 Activity正在停止,仍可见,正常情况下,紧接着onStop就会被调用。在特殊情况下,如果这个时候快速地回到当前Activity,那么onResume就会被调用(极端情况)。onPause中不能进行耗时操作,会影响到新Activity的显示。因为onPause必须执行完,新的Activity的onResume才会执行。

(6) onStop():表示Activity即将停止,不可见,位于后台。可以做稍微重量级的回收工作,同样不能太耗时。

(7) onDestory():表示Activity即将销毁,这是Activity生命周期的最后一个回调,可以做一些回收工作和最终的资源回收。

注意:

如果新Activity采用了透明主题,那么当前Activity不会回调onStop。

onPause必须执行完,新Activity的onResume才会执行。

onStart和onStop对应,onStart时Activity可见,onStop时Activity不可见;onResume和onPause对应,onResume时Activity位于前台,onPause时Activity不在前台。

1.2 异常情况下的生命周期

(1)系统配置发生改变,Activity被杀死并重建

onSaveInstanceState:在Activity由于异常情况下终止时,系统会调用onSaveInstanceState来保存当前Activity的状态。这个方法的调用是在onStop之前,它和onPause没有既定的时序关系,该方法只在Activity被异常终止的情况下调用。

onRestoreInstanceState:当异常终止的Activity被重建以后,系统会调用onRestoreInstanceState,并且把Activity销毁时onSaveInstanceState方法所保存的Bundle对象参数同时传递给onRestoreInstanceState和onCreate方法。因此,可以通过onRestoreInstanceState方法来恢复Activity的状态,该方法的调用时机是在onStart之后。

其中onCreate和onRestoreInstanceState方法来恢复Activity的状态的区别:onRestoreInstanceState回调则表明其中Bundle对象非空,不用加非空判断。onCreate需要非空判断。建议使用onRestoreInstanceState。

当系统配置的某些内容发生改变时,我们不想系统重新创建Activity,可以给Activity指定configChanges属性。几个常见的configChanges的项目和含义如下:

  • local:设备的本地位置发生改变,一般指切换了系统语言。
  • keyboardHidden:键盘的访问性发生改变,比如用户调出了键盘。
  • orientation:屏幕方向发生了改变。
  • screenSize:当屏幕的尺寸信息发生了改变,旋转屏幕时尺寸会发生变化。(当minSdkVersion和targetSdkVersion都低于13时,此项不会导致Activity重启)

例如,不想屏幕旋转时Activity重启:

android:configChanges = "orientation| screenSize"

此时旋转屏幕会调用onConfigurationChanged方法。

(2)资源内存不足,低优先级Activity被杀死

Activity优先级的划分和下面的Activity的三种运行状态是对应的。

(1) 前台Activity——正在和用户交互的Activity,优先级最高。

(2) 可见但非前台Activity——比如Activity中弹出了一个对话框,导致Activity可见但是位于后台无法和用户交互。

(3) 后台Activity——已经被暂停的Activity,比如执行了onStop,优先级最低。

当系统内存不足时,会按照上述优先级从低到高去杀死目标Activity所在的进程。如果一个进程中没有四大组件在执行,那么这个进程将很快被系统杀死,比较好的方法是将后台工作放到Service中从而保证进程有一定的优先级。

2.Activity的启动模式

2.1 四种启动模式

(1)标准模式(standard)

系统的默认模式。每启动一次Activity,就会创建一个新的Activity实例并置于栈顶。谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。

特殊情况,如果在Service或Application中启动一个Activity,其并没有所谓的任务栈,可以为待启动的Activity指定FLAG_ACTIVITY_NEW_TASK标记位,创建一个新栈。**

(2)栈顶复用模式(singleTop)

如果新Activity已经位于任务栈栈顶,那么此Activity就不会重建,而是重用栈顶的实例。并回调如下方法:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
}

由于不会重建一个Activity实例,则不会回调其他生命周期方法。
如果栈顶不是新的Activity,就会创建该Activity新的实例,并放入栈顶。

(3)栈内复用模式(singleTask)

该模式是一种单例模式,即一个栈内只有一个该Activity实例。如果Activity指定的栈不存在,则创建一个栈,然后创建Activity压入栈内。如果Activity指定的栈存在,但是其中没有该Activity实例,则会创建Activity并压入栈顶,如果其中有该Activity实例,则把该Activity实例之上的所有Activity杀死清除出栈,让该Activity实例处在栈顶,然后调用onNewIntent()方法。

该模式可以通过在AndroidManifest文件的Activity中指定该Activity需要加载到那个栈中,即singleTask的Activity可以指定想要加载的目标栈。singleTask和taskAffinity配合使用,指定开启的Activity加入到哪个栈中。

<activity android:name=".Activity1"
 android:launchMode="singleTask"
 android:taskAffinity="com.lvr.task"
 android:label="@string/app_name">
</activity>

关于taskAffinity的值:每个Activity都有taskAffinity属性,这个属性指出了它希望进入的Task。如果一个Activity没有显式的指明该Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果Application也没有指明,那么该taskAffinity的值就等于包名。taskAffinity的值为字符串,中间必须包含包名分隔符“.”

(4)单实例模式(singleInstance)

加强版的栈内复用模式(singleTask),具有此种模式的Activity只能单独地位于一个任务栈中
打开该Activity时,直接创建一个新的任务栈,并创建该Activity实例放入新栈中。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例。

2.2 特殊情况:

① 前台任务栈调用启动模式为SingleTask的后台任务栈中的Activity,整个后台任务栈都会被切换到前台。singleTask具有clearTop特性,把之上的栈内Activity清除。

② 当TaskAffinity和allowTaskReparenting结合时产生特殊效果。应用A启动应用B的Activity C后,如果Activity C的allowTaskReparenting为true,那么当应用B启动后,Activity C会从应用A的任务栈转移到任务B的任务栈中,此时B应用不是启动主Activity,而是重新显示已经被应用A启动的Activity C。

2.3 给Activity指定启动模式

① 通过AndroidManifest指定

<activity android:name=".Activity1"
 android:launchMode="singleTask"
 android:label="@string/app_name">
</activity>

② 通过Intent设置标志位指定

Intent intent = new Intent();
intent.setClass(this,SecondActivity,class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

第二种方式的优先级要高于第一种方式。

3.Activity的Flags

(1)FLAG_ACTIVITY_NEW_TASK
其效果与指定Activity为singleTask模式一致。

(2)FLAG_ACTIVITY_SINGLE_TOP
其效果与指定Activity为singleTop模式一致。

(3)FLAG_ACTIVITY_CLEAR_TOP
具有此标记位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。如果和singleTask模式一起出现,若被启动的Activity已经存在栈中,则清除其之上的Activity,并调用该Activity的onNewIntent方法。如果被启动的Activity采用standard模式,那么该Activity连同之上的所有Activity出栈,然后创建新的Activity实例并压入栈中

(4)FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
具有这个标记的Activity不会出现在历史Activity列表中,等同于在XML中指定Activity的属性android:excludeFromRecents=”true”。

4.IntentFilter的匹配规则

匹配过滤列表,同时匹配过滤列表中的action/category/data信息,才能隐式调用启动Activity。

(1)action匹配规则

Intent必须存在action,且和过滤规则的其中任意一个action的字符串值完全相同(区分大小写)。如果Intent中没有指定action,那匹配失败。

(2)category匹配规则

Intent中如果出现了category,不管有几个category,对于每个category来说,它必须是过滤规则中已经定义了的category。Intent可以没有category,仍然可以匹配成功。因为系统在调用startActivity或者startActivityForResult的时候会默认为Intent加上“android.intent.category.DEFUALT”这个cate。为了Activity能够接受隐式调用,必须在intent-filter中指定android.intent.category.DEFUALT这个category。

(3)data的匹配规则

如果过滤规则中定义了data,那Intent中必须也要定义可匹配的data。data包括mimeType和URI两部分。mimeType指媒体类型。URI的结构为:

<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

例如:

http://www.baidu.com:80/search/info

如下过滤规则:

<intent-filter>
   <data android:mimeType="image/*">
   .....
 </intent-filter>

虽然没有指定URI,但是URI有默认值,为content和file。所以Intent的URI的schema必须为content或者file才能匹配。匹配上述过滤规则的Intent如下:

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

示例

Activity中的过滤规则:

<intent-filter>
   <action androd:name="com.hunst.action_1">
   <action androd:name="com.hunst.action_2">
   <category androd:name="com.hunst.category_1">
   <category androd:name="com.hunst.category_2">
   <category androd:name="android.intent.category.DEFAULT">
   <data android:mimeType="text/plain">
</intent-filter>

完全匹配上面过滤规则的Intent:

Intent intent = new Intent("com.hunst.action_1");
intent.addCategory("com.hunst.category_1");
intent.setDataAndType(Uri.parse("file://abc"),"text/plain");
startActivity(intent);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值