Android学习感悟之Activity

Android学习感悟之Activity,包含生命周期、启动模式以及一些Activity中常用的方法。

在Android开发中,用的最为平凡的,最不能少的就是Activity了,所以作为学习感悟的第一篇我觉得再适合不过了。还记得刚接触Android的时候,第一件事就是找到Hello World是怎么显示到手机上的,那就是我第一次接触到Activity。话不多说,直接进入正题。

Activity的生命周期

Activity,我们常常把它译为活动,大家都知道任何一件事都有他的流程,而在Android中把他叫做生命周期,一件事的流程无外乎都会包含,开始,经过,结束,而在Android中Activity同样有这些过程,只不过在程序中是由系统去回调这些步骤的,下边我们可以先看一下,这些过程有哪些。
来自于Android developer training:

basic-lifecycle.png

可以看到依次包含:onCreate()->onStart()->onResume()->onPaused()->onStop()->onDestroy()

Activity的开始:onCreate->onStart()->onResume();

Activity的结束:onPaused()->onStop()->onDestroy;

Activity的经过:是由界面可视化后,与用户交互的过程。这里边涉及到一个名词——可视化,意思很简单,就是由界面不可见到可见的这个过程。

正常情况下Activity生命周期

这个图其实已经包含了所有正常情况下Activity生命周期的内容。而正常的生命周期的回调也有很多种情况,接下来会逐一介绍。(注:接下来说的启动都是指第一次启动和标准模式的启动方式)

1、正常的启动和关闭。

(1)启动Activity A,系统就会调用onCreate,创建这个Activity,创建成功后会马上调用onStart,这时候Activity就已经可见了,但还没有出现在在前台,还无法交互,紧接着会调用onResume,这时候界面就已经可见了,这时候这一次启动就已经走完了;

(2)结束Activity A,会先调用onPause,调用完成后界面就不分不可见了,紧接着这时候会掉用onStop,调用完成后就完全看不见了,最后就会调用onDestroy去销毁这个Activity A,这时候这个Activity就结束了。

2、启动Activity A后再从A启动和结束Activity B过程中,Activity A的生命周期的回调。

(1)当A启动好后,从A启动B,这时候A很明显会被B遮住,所以从视觉上我们应该可以猜到应该会调用onPause和onStop,实际上也确实是这样;

(2)结束B,这时候A就应该重新可见,系统便会给我们依次回调onRestart->onSatrt->onResume方法,这时候A的界面又重新可见了。

(3)注意:这里边有两个知识点比较特殊,(1)如果B的主题被设置被背景透明,那么从A启动B时,A不会调用onStop方法,具体原因暂时还未深究;(2)A的onPause和B的onResume谁先调用,从源码中可以得到答案,应该是A的onPause先调用,所以为了用户体验,我们不应该在onPause中做耗时的操作。

注意:启动dialog并不会回调任何activity的生命周期

异常情况下的生命周期

上边说到正常的生命周期会有那么几种情况,那什么叫不正常的呢?其实就是Activity在资源相关的系统配置发生改变或者系统内存不足时被杀死,并重新创建的时候,这时候就不大相同了。接下来分析这两种情况。

1、资源以及相关配置发生改变,被销毁并重建

资源加载机制比较复杂,我暂时还没有太多了解,这里也就不过多解释;举个出现这种情况的例子吧,比如程序有两张图片对应横屏和竖屏时加载,当Activity从竖屏转到横屏时,由于系统配置发生改变,在默认情况下,Activity就会被销毁并重建,当然我们也可以阻止重建该Activity。

(1)在这种情况下Activity的销毁依然还是会调用onPause,onStop,onDestroy方法,同时还会调用onSaveInstanceState,通过参数Bundle来保存当前Activity的状态,该方法的回调早onStop之前,和onPause没有固定的顺序;重建的时候除了会调用onCreate,onStart,onResume以外还会多调用一个onRestoreInstanceState方法,通过参数Bundle来恢复状态,该方法在onStart之后调用。值得注意的是,系统本身在这两个方法里已经为我们保存了一些数据,例如View的数据,通过查看源码我们可以找到在View中也有onSaveInstanceState和onRestoreInstanceState方法,用来保存和恢复View中的一些数据,而这个过程是由Activity通知Window,window通知decorView,decorView再一一通知子View来完成的,通知的过程和View的绘制和事件回调流程一致,这是一种委托的思想。

2、资源内存不足导致低优先级的Activity被销毁。

这种情况不好模拟,但是他的数据恢复和第一种情况是完全一致的,而这里描述一下Activity的优先级,从高到低分为:

(1)前台Activity——正在交互的

(2)可见但非前台——例如弹出一个Dialog,无法直接交互的

(3)后台Activity——被暂停的,执行了onStop方法的

3、阻止配置改变时被销毁重建的方法

我们可以在AndroidManifest.xml文件中给Activity指定configChanges属性,并根据不同情况赋予不同的值即可保证改变时不被销毁重建,下边就举几个例子来说明:

(1)当我们只考虑屏幕旋转引起的重启时,我们只保留竖屏或者横屏,这样就让旋转时不改变布局方向来保证不被销毁重启,我们可以给Activity指定screenOrientation属性,属性值如下:

android:screenOrientation="portrait"//保留竖屏
android:screenOrientation="landscape"//保留横屏

该属性涉及到横竖屏的属性值就有好多个,其具体含义如下:

Value Meaning
"unspecified" 默认值 由系统来判断显示方向.判定的策略是和设备相关的,所以不同的设备会有不同的显示方向
"landscape" 横屏显示(宽比高要长)
"portrait" 竖屏显示(高比宽要长)
"user" 用户当前首选的方向
"behind" 和该Activity下面的那个Activity的方向一致(在Activity堆栈中的)
"sensor" 有物理的感应器来决定。如果用户旋转设备这屏幕会横竖屏切换
"nosensor" 忽略物理感应器,这样就不会随着用户旋转设备而更改了 ( "unspecified"设置除外 )

(2)还有一种就是使用configChanges属性,并设置为:

 android:configChanges="orientation"

同时设置多个属性值时,只需用“|”隔开即可。下边还是看一下该属性常用的属性值的含义吧:如下:

Value Meaning
"orientation" 屏幕方向发生了改变,例如旋转手机屏幕
"locale" 本地位置放生改变,一般为切换了系统语言
"keyboardHidden" 键盘的可访问性发生了改变,例如用户调出了键盘
"screenSize" 当屏幕尺寸发生改变,例如屏幕旋转也会导致屏幕尺寸发生改变,若minSdkVersion或者targetSdkVersion任一大于等于13,则就会引起重启
"smallestScreenSize" 当接入外接显示器时,若minSdkVersion或者targetSdkVersion任一大于等于13,则就会引起重启

Activity的启动模式

1、启动模式介绍

Android系统为了保证资源不浪费,尽可能的不要创建多余的Activity,所以引入了启动模式,Actvity的启动模式包含:standard、singleTop、singleTask、singleInstance。说到启动模式,必然就会涉及到任务栈的问题,这是系统为我们提供的管理Activity的一个结构,栈的特点就是先进后出。那Activity创建时是怎么进栈的呢,这个就要看不同的启动模式,来区别对待了。

(1)standard:标准模式,这是系统默认的启动模式。每次启动一个Activity都会重新创建一个Activity实例,不管这个Activity是否已经存在实例。这时候被启动的Activity进入的栈就是启动它的Activity所在的任务栈。当我们使用ApplicationContext去启动standard模式的Activity时是会报错的,而ApplicationContext并没有任务栈。解决办法是为要启动的Activity指定一个FLAG_ACTIVITY_NEW_TASK标记位,这时就能为新创建的Activity创建一个新的任务栈。

(2)SingleTop:栈顶复用模式。如果新的Activity的实例已经位于栈顶,则不会被重新创建,只会回调onNewIntent方法,便可拿到当前请求的信息。若不再栈顶,则依然会重新创建一个实例。

(3)singleTask:栈内复用模式。这其实是一种单例模式,只要该Activity所需的任务栈中存在其实例,便不会重新创建该实例,只会回调onNewIntent方法,而在该Activity上的Activity会被移除掉,从而使该Activity移动到栈顶。若不存在,便会在该Activity所需的任务栈中创建实例,若其所需的任务栈不存在,则会先创建该任务栈。但是使用ApplicationContext去启动一个SingleTask模式的Activity依旧会报错。其中说到了Activity所需的任务栈,这个就是要使用TaskAffinity属性来设定,默认任务栈的名字都是包名,这个属性只有和singleTask一起使用才有效。

(4)singleInstance:单实例模式。这个就是加强版的singleTask,他只会单独存在于一个任务栈中。

2、启动模式的应用场景

Mode Use Case
standard 默认都是使用该模式
singleTop 适合接受通知并启动的内容展示页面,好比新闻详情界面,收到10个新闻推送,每个都要打开新闻详情,若打开十次那肯定是不合适的。
singleTask 适合作为程序入口点,例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。
singleInstance 适合需要与程序分离开的页面。例如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B。

Activity中常用的方法

1、生命周期中的各个方法;
2、finish()->关闭Activity;
3、onBackPressed()->按返回键回调,默认实现是finish掉Activity;
4、startActivity(...)->分别表示启动Activity;
5、startActivityForResult(...)->启动Activity并能接受启动的那个Activity回传的参数,接收参数使用onActivityResult(...)方法;
6、overridePendingTransition(...)->启动Activity的启动动画,必须紧跟在startActivity()或者finish()的后边才有效;
7、runOnUiThread(...)->在主线程中运行,通常在子线程中想要更新界面时使用,内部使用Handler实现;
8、getResource()->获取资源,方便获取图片、颜色、尺寸、文本等资源;
9、registerReceiver(...)以及unregisterReceiver(...)->注册广播以及注销广播;
10、bindService()以及unbindService()->绑定服务以及解绑服务;
11、getContentResolver()->用于获取contentProvider数据。

总结

写到这里基本上Activity的生命周期和启动模式就介绍的差不多了,如果说还差什么的话,我觉得就应该是Activity的标志未以及IntentFilter的匹配规则,这两个内容留到Intent中再写吧,这篇感觉已经太多了。如果有任何不对的地方,请发我邮件,感谢~

参考资料

《Android开发艺术探究》、Android developer training。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容