Activity的四种启动模式应⽤场景
在这⾦三银四的时间⾥⼀个哥们忽然⼀本正经的问我Activity的启动模式和具体的应⽤模式;我也⼀想是啊,平是不太注意结果到了 关键的时刻卡壳了,感觉未⾬绸缪⼀下,做个记录:
⼀、Activity四种启动模式:
(⼀)、基本描述
1. standard:标准模式:如果在mainfest中不设置就默认standard;standard就是新建⼀个Activity就在栈中新建⼀个activity实例;
2. singleTop:栈顶复⽤模式:与standard相⽐栈顶复⽤可以有效减少activity重复创建对资源的消耗,但是这要根据具体情况⽽定,不能
⼀概⽽论;
3. singleTask:栈内单例模式,栈内只有⼀个activity实例,栈内已存activity实例,在其他activity中start这个activity,Android直接把
这个实例上⾯其他activity实例踢出栈GC掉;
4. singleInstance :堆内单例:整个⼿机操作系统⾥⾯只有⼀个实例存在就是内存单例;
在singleTop、singleTask、singleInstance 中如果在应⽤内存在Activity实例,并且再次发⽣startActivity(Intent intent)回到Activity后,由于并不是重新创建Activity⽽是复⽤栈中的实例,因此Activity再获取焦点后并没调⽤onCreate、onStart,⽽是直接调⽤了onNewIntent(Intent intent)函数;
(⼆)、taskAffinity属性
taskAffinity属性和Activity的启动模式息息相关,⽽且taskAffinity属性⽐较特殊,在普通的开发中也是鲜有遇到,但是在有些特定场景下却有着出其不意的效果。
taskAffinity是Activity在mainfest中配置的⼀个属性,暂时可以理解为:taskAffinity为宿主Activity指定了存放的任务栈[不同于App中其他的Activity的栈],为activity设置taskAffinity属性时不能和包名相同,因为Android团队为taskAffinity默认设置为包名任务栈。
taskAffinity只有和SingleTask启动模式匹配使⽤时,启动的Activity才会运⾏在名字和taskAffinity相同的任务栈中。
(三)、Intent中标志位设置启动模式
在上⽂中的四种模式都是在mainfest的xml⽂件中进⾏配置的,GoogleAndroid团队同时提供另种级别更⾼的设置⽅式,即通过
Intent.setFlags(int flags)设置启动模式;
1. FLAG_ACTIVITY_CLEAR_TOP : 等同于mainfest中配置的singleTask,没啥好讲的;
2. FLAG_ACTIVITY_SINGLE_TOP: 同样等同于mainfest中配置的singleTop;
3. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS: 其对应在AndroidManifest中的属性为
android:excludeFromRecents=“true”,当⽤户按了“最近任务列表”时候,该Task不会出现在最近任务列表中,可达到隐藏应⽤的⽬的。
4. FLAG_ACTIVITY_NO_HISTORY: 对应在AndroidManifest中的属性为:android:noHistory=“true”,这个FLAG启动的
Activity,⼀旦退出,它不会存在于栈中。
5. FLAG_ACTIVITY_NEW_TASK: 这个属性需要在被start的⽬标Activity在l⽂件配置taskAffinity的值【必须和
startActivity发其者Activity的包名不⼀样,如果是跳转另⼀个App的话可以taskAffinity可以省略】,则会在新标记的Affinity所存在的taskAffinity中压⼊这个Activity。
个⼈认为在上述Flag中FLAG_ACTIVITY_NEW_TASK是最为重要的⼀个flag,同时也需要注意的是⽹上有很多是瞎说的;⽽且也是个⼈唯⼀⼀个在实际开发中应⽤过的属性;先说说个⼈应⽤⽰例:
1.在Service中启动Activity;
2.App为系统Launcher时,跳转到⽆法退出时⽤到;
⾄于为啥看下⽂开发的案例就知道了。
(四)、startActivity场景
Activity的启动模式的应⽤的设置是和它的开发场景有关系的,在App中打开新的Activity的基本上分为两种情况:
1. ⽬标Activity是本应⽤中的Activity,即它的启动模式是可以直接在fanifest中配置或者默认为standard,任务栈也可以⾃⼰随意设置;
2. ⽬标Activity是第三⽅App中的Activity,这个时候就需要先考虑打开新Activity的是和⾃⼰App放在同⼀任务栈中还是新的task中【这个是
很重要的因为在Android的机制中:同⼀个任务栈中的activity的⽣命周期是和这个task相关联的[具体实例见下⽂]】,然后考虑Activity的启动模式; 所以Android提供了优先级更⾼的设置⽅式在Intent.setFlags(int flags),通过这setFlags就可以为打开第三⽅的App中Activity设置任务栈和启动模式了,具体设置就⾃⼰去看源码了。
⼆、Activity四种启动模式常见使⽤场景:
这也是⾯试中最为长见的⾯试题;当然也是个⼈⼯作经验和借鉴⽹友博⽂,如有错误纰漏尽请诸位批评指正;
LauchMode Instance
standard邮件、mainfest中没有配置就默认标准模式
singleTop登录页⾯、WXPayEntryActivity、WXEntryActivity 、推送通知栏
singleTask 程序模块逻辑⼊⼝:主页⾯(Fragment的containerActivity)、WebView页⾯、扫⼀扫页⾯、电商中:购物界⾯,确认订单界⾯,付款
界⾯
singleInstance系统Launcher、锁屏键、来电显⽰等系统应⽤
三、启动模式在实际开发中⼩插曲
最近的项⽬就出现了⼀个由于启动模式导致的问题,先开还是⼀脸闷还是同事最先想到问题缘由于是做个记录长个教训吧。最近搞的App是在⼀个cpu⽐较low的Android系统的设备上跑的,⽽且是App是作为LAUNCHER启动的,并且在App的⼀个功能就是点击直接跳转到登录LauncherUI页[如果有登录会⾃动到聊天页⾯]的,这个听起也是很普通的⼀个功能。但是还是出了⼀个⼩问题。
(⼀)、问题复现:
开机后App作为launcher启动,然后打开LauncherUI加载页【未登录】到登录页,然后点返回键【系统返回键】不能也退出返回到原来我们的launcher的App中去了,然后Android⼤法在底部导航栏中查看系统任务【有那些应⽤在后台】,结果显⽰⼀个也没有;这样就是⼀时间尴尬了退不出了;
(⼆)、问题定位:
1.点击返回键【系统返回键】页⾯没有退出:的登录页⾯Activity拦截了返回键 KeyEvent.KEYCODE_BACK 事件【只是将应⽤隐藏在后台不退出,然后回到桌⾯】,所以登录Activity没有销毁;
2.系统导航栏查看正在运⾏的应⽤为空,实际上是正在运⾏我们的App[launcher⽽且放在在system/app下]和的,两个问题缘由:
1. 我们的App作为launcher被Android作为系统应⽤任务栈了所以没有显⽰;
2. 是在launcherApp中打开的⽽且打开代码是并没有设置LauncherUI的启动模式和任务栈,Android默认是在同⼀个任务栈
中了,所以在查看任务栈时看不到应⽤,⽽且由于App是launcher作为系统任务就显⽰没有应⽤程序了;
(三)、解决办法
我们的期望是即使不登录同样点返回键就可以直接返回到我们App的页⾯中;
根据已经点位到问题进⾏解决⼀个基本思路是:⽤户点返回键后杀死的Activity,回到我们App页⾯中;
具体代码就是
//修改之前
Intent intent = new Intent();
intent.setClassName("", "ui.LauncherUI");
context.startActivity(intent);
//修改之后是这样的
单例模式的几种实现方式Intent intent = new Intent();
intent.setClassName("", "ui.LauncherUI");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
其实代码中只是设置新打开在新的任务栈中,这样就是及时在LauncherUI的页⾯中拦截了返
回键【只是将应⽤隐藏在后台不退出然后回到桌⾯】,这样我们App最为launcher,所以就回到我们App了。同样这样在在导航栏中查看真正运⾏任务就可以看到了;
(四) 、新的问题
在添加上Intent.FLAG_ACTIVITY_NEW_TASK之后是需要新建⼀个任务栈打开App的,虽然是解决了不能返回的问题,但是也引发新的问题:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
1.⽤户点返回键后并没有退出:在界⾯上看到是回到桌⾯App中了,其实并没有退出任然在后台运⾏;这个问题其实普遍存在,⽽且开发者基本上都是对⽤户采取理性欺骗【或者隐瞒】,现实中⽤户也是都已经接受;
2.点击跳转到明显卡顿:以前打开新的App是在⼀个任务栈中的,打开新App页⾯和在同⼀App页⾯跳转感觉基本上是⼀瞬间的,⽤户感觉不到是在App之间跳转的,设置Intent.FLAG_ACTIVITY_NEW_TASK之后是需要新建⼀个任务栈打开App的,点击后有明显的停顿【CPU越差劲越明显】⽤户体验明显变差了。
四、Activity中其他常见问题
(⼀) ⽣命周期
1.正常⽣命周期:
onCreat() onStart() onResume() onPause() onStop() onDestroy()
2.横竖屏切换
(1).未设置
configChanges:
(⼀) 、Intent的基本应⽤
在Android中Intent是在四⼤组件之间进⾏交互与通讯,也可以在应⽤之间通讯。其底层的通信是以Binder机制实现的,在物理层则是通过共享内存的⽅式实现的。
1.Intent属性
Intent的属性有:component(组件)、action、category、data、type、extras、flags;所有的属性也是各显神通,满⾜开发者的各种需要满⾜不同场景;
component: 显然就是设置四⼤组件的,将直接使⽤它指定的组件,借助这⼀属性可以实现不同应⽤组件之间通讯;
action: 是⼀个可以指定⽬标组件⾏为的字符串,开发⼈员可以⾃定义action通过匹配action实现组件之间的隐⼠跳转,当然Android系统也已经预定部分String作为系统应⽤Action,例如打开系统设置页⾯等等;
data: 通常是URI类型或者MIME类型格式定义的操作数据;表⽰与动作要操纵的数据
data中长见的MIME类型数据;
tel://:号码数据格式,后跟电话号码。
mailto://:邮件数据格式,后跟邮件收件⼈地址。
smsto://:短息数据格式,后跟短信接收号码。
content://:内容数据格式,后跟需要读取的内容。
file://:⽂件数据格式,后跟⽂件路径。
market://search?q=pname:pkgname:市场数据格式,在Google Market⾥搜
data中URI
data元素组成的URI模型:scheme://host:port/path 例如:file://com.st:520/mnt/sdcard;
Category: 属性⽤于指定当前动作(Action)被执⾏的环境;
type: 对于data范例的描写;
extras和flags 这两个太熟悉了就不在重复;
2.Intent的隐⼠与显⽰
显⽰Intent是最长见的,也是使⽤最为频繁的;但是很显然隐⼠Intent更为强的尤其是在模块化的时代;
(⼆) 、Activity异常⽣命周期与应⽤
这个过程中⼏个核⼼的函数和参数是:Bundle[onCreate(Bundle savedInstanceState)],onSaveInstanceState(Bundle outState)、onRestoreInstanceState(Bundle savedInstanceState);
1.系统配置改变引起异常;
这⾥的系统配置改变是指由于横竖屏切换等引起的Activity⽣命周期的变化,进⽽引发的资源的变化。在Android中系统配置改变是会引起Activity销毁重建的,例如横竖屏切换,只是切换时间差太⼩,⽤户眼睛不能察觉⽽已。activity重建的时候就在之前Activity销毁前,系统会先调⽤onSaveInstanceState(Bundle outState)存储当时各种状态,在新建Activity中Android会通过
onRestoreInstanceState(Bundle savedInstanceState)读取数据并⾃动恢复到之前Activity的View,当然在Activity中开发者⾃⼰的代码逻辑就需要⾃⼰处理啦。
触发onSaveInstanceState(Bundle outState)的条件:
1、当⽤户按下HOME键时。
2、从最近应⽤中选择运⾏其他的程序时。
3、按下电源按键(关闭屏幕显⽰)时。
4、从当前activity启动⼀个新的activity时。
5、屏幕⽅向切换时(⽆论竖屏切横屏还是横屏切竖屏都会调⽤)。
在前4种情况下,当前activity的⽣命周期为:
onPause -> onSaveInstanceState -> onStop。
2.系统回收引起异常
在Android系统内存不⾜时,同时Activity失去焦点后被系统给回收后,Activity 再次被创建时,通过onSaveInstanceState 和onRestoreInstanceState来存储恢复数据再次显⽰在屏幕上之前的View等状态;
3.Activity异常基础处理
1.最常见的是在onCreate(Bundle savedInstanceState)中通判断savedInstanceState是否为空,恢复Activity中的数据体;
2.另⼀种就是根据应⽤场景在mainfest中配置各种参数尽可能减少由于配置参数引起的Activity异常;
3.使⽤onConfigurationChanged⽅法代替onRestoreInstanceState实现恢复数据逻辑,更⾼级的⾃然就是性能优化、实时监视的思路啦;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论