android开发艺术探索 笔记,android开发艺术探索 笔记(一)

第一章Activity的启动与生命周期

正常情况下的启动状态

onCreate加载布局,初始化数据

onStart界面可视化,但尚在后台,不可交互。

onRestart从不可见(onStop)到可见(onStart)需要经过onRestart

onResume从后台到前台,Activity变得可以交互。

onPause一般onPause后紧接着onStop,所以不推荐将耗时的操作放在这里。

×当新的Activity为透明时,原先Activity还是可视的,因而不会执行onStop

onStop从不可互动到不可视,如点击home键回到桌面,这是Activity一般还没有被销毁,等待着onRestart->onStart->onResume重新恢复状态

onDestroy销毁Activity,并进行一些回收工作,如关闭数据库等。

bb632d3a489a

一张应该出现过很多遍的图

基于书上说的屏幕的点亮熄灭以及手指的触摸,我个人试了一下

界面一切·从简,就是默认emptyActivity的界面

每个方法写都写一个Log.d("ActivityLife","onXXXX");//XXXX视方法而定

Activity刚启动时: onCreate->onStart->onResume

bb632d3a489a

启动时

点击返回键,关闭程序时:onPause->onStop->onDestroy

bb632d3a489a

退出

点击home键:onPause->onStop

bb632d3a489a

后台

从后台唤醒:onRestart->onStart->onResume

bb632d3a489a

唤醒

一直到这里,都和我们在前面的理论是一样的。

锁屏时,其实和挂到后台是一样的

bb632d3a489a

锁屏

当唤醒屏幕时,如果有密码的话,唤醒之后是要输入密码,这个时候Activity的界面依旧不可见,因此不会调用以上的任何方法,只有解锁后,Activity重新可见时,又会执行之前从后台唤醒相同的步骤

bb632d3a489a

唤醒

从Activity1启动Activity2,会先执行Activity1的onPause,然后创建Activity2(onCreate->onStart->onResume)再执行Activity1的onStop.

bb632d3a489a

一些小细节

关于生命周期的重点在于onStart、onStop控制的是Activity是否可见(在后台),onResume、onPause控制的是Activity是否在前台可供操作。

异常情况下的生命周期

而onSaveInstanceState是系统自行销毁Activity时对数据的保存。重新打开时调用onRestoreInstanceState恢复数据。即异常情况下销毁Activity时,会调用这两个方法恢复数据。而横竖屏就属于这种异常情况。

bb632d3a489a

横竖屏

这里我们可以发现,onSaveInstanceState是在onStop前执行的,而onRestoreInstanceState是在onStart后执行的。

当Activity异常情况下的情况下需要重新创建时,系统会默认我们保存当前Activity的视图结果,并在Activity重启后为我们恢复这些数据,比如文本框用户输入的数据,ListView的滚动位置等

关于保存和恢复View的层次结构,系统的工作流程:首先Activity会调用onSaveInstanceState去保存数据,然后Activity会委托Window去保存数据,接着Window会委托它上面的顶级容器去保存数据,顶层容器一般是DecorView(ViewGroup);最后顶层容器再去一一通知它的子元素保存数据,这样整个数据的保存过程就完成了。

×这里还要注意一下,onSaveInstanceState还有一个两个参数的方法,是不会在异常状态中调用的。

资源不足导致的Activity被销毁

Activity的优先级

正在和用户交互的Activity优先级最高: onResume

可见但非前台的Activity优先级次之:onPause

后台Activity优先级最低:onStop

当系统内存不足时会杀死目标Activity的进程,再用onSaveInstanceState和onRestoreInstanceState进行恢复。

如果一个进程在后台没有四大组件在运行,很容易被系统回收,因此可以在后台放入一个service提高优先级。

configChanges

当系统配置发生改变时,Activity会重新创建,如果在Activity指定configChanges属性,Activity就会执行configChanges的属性,而不用重新创建了。

如横竖屏切换:

manifests中配置

android:configChanges = "orientation"

//多个属性用|

@Override

public void onConfigurationChanged(Configuration newConfig) {

super.onConfigurationChanged(newConfig);

Log.d("ActivityLife","onConfigChanged:"+newConfig.orientation);

}

Activity创建后,从竖屏到横屏再到竖屏的过程中

bb632d3a489a

没用调用onSaveInstanceState和onRestoreInstanceState方法,也没有重新创建Activity

bb632d3a489a

configChanges的一些属性

常用的是locale、orientation和keyboardHidden

×android4.0以上orientation要注意配置screensize,不然还是会调用onCreate

使用configChanges:orientation时,就不会使用oSaveInstanceState和onRestoreInstanceState来恢复数据了,因为都没有销毁。。。

Activity的启动模式

Activity的LaunchMode

任务栈是一个“后进先出”的栈结构,每次finish()处于前台的Activity就会出栈,直到栈为空为止,当栈中无任何Activity的时候,系统就会回收这个任务栈。

standard

默认的模式,每次启动都会创建一个新的Activity到任务栈中。Activity A启动Activity B会让B进入A所在的任务栈中,就是这种特性导致,ApplicationContext没有任务栈,context启动standard的Activity时会发生错误。这时候需要在Intent中加入FLAG_ACTIVITY_NEW_TASK,这时实际上是以singleTask启动的。

Actvity1启动Activity1

bb632d3a489a

销毁上面的Activity1

bb632d3a489a

singleTop

栈顶复用模式,若该Activity处于任务栈的栈顶,那么就不会重新创建该Activity。

(Activity1为singleTop)

Activity1启动Acticity1时:

bb632d3a489a

只调用onPause->onNewIntent->onResume

销毁时:

bb632d3a489a

只有单个Activity在栈中

Activity1启动Activity2再启动Activity1时:

bb632d3a489a

捕获.PNG

会重新创建Activity1

销毁时:

bb632d3a489a

销毁最上面的Activity1

bb632d3a489a

销毁Activity2

singleTask

栈内复用模式。这种模式下,Activity在一个栈中存在,那么多次启动该Activity都不会重新创建实例,和sinleTop一样,系统会回调其onNewIntent。如果启动的Activity没有所需要的任务栈,就会先创建任务栈再创建Activity。singleTask默认具有clearTop的效果,具有该模式的Activity会让其之上的Activity全部出栈。

Activity1处于栈顶时启动Activity1

bb632d3a489a

这里和singleTop是一样的

Activity1启动Activity2再启动Activity1

bb632d3a489a

注意这里,由于不会生成新的Activity1,所以调用onRestart->onStart->onResume,而Activity2会直接被销毁。

singleInstance

单实例模式。这是一种加强的singleTask模式,除了具备singleTask的特性之外,具有该模式的Activity只能单独位于一个任务栈中;比如Activity A是singleInstance模式的,当A启动后,系统会为它创建一个新的任务栈,后续的启动均不会创建新的Activity,除非这个任务栈被系统销毁了。

这里可以这么理解,singleInstance会创建一个新的任务栈,这个任务栈中只有自己一个实例,启动其他Activity会重新创建一个任务栈,供其他的Activity使用。此时Activity的销毁顺序与创建顺序无关,和任务栈内Activity的顺序有关。当销毁时处在singleInstance所在的任务栈,那么该任务栈会被销毁,跳转到另一个任务栈的栈顶,再根据这个任务栈Activity的次序进行销毁。而当销毁工作处于另一个任务栈时,会先选择清空这个任务栈的所有实例,在跳转到唯一的singleInstance所在任务栈的实例。

LaunchMode的使用方法

在manifests中activity下

android:launchMode="singleInstance"

或者在intent中addFlag

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

这里第二种方法的优先级更高,而区别在于第一种方法不能使用FLAG_ACTIVITY_CLEAR_TOP,第二种不能设置singleInstance。

这里书中还提到了TaskAffinity和AllowTaskReparenting两个属性

TaskAffinity标识了Activity所需的任务栈的名字

AllowTaskReparenting="true"时,例子如下:

A启动B的ActivityC,ActivityC刚好是这个属性,此时C会在A的任务栈中。当按下home键再打开应用B时,会直接打开ActivityC,而不是默认的首页面。此时ActivityC会从A的任务栈转移到B的任务栈

adb shell dumpsys activity命令可以详细的了解当前任务栈情况

Activity的Flags

FLAG_ACTIVITY_NEW_TASK

即singleTask

FLAG_ACTIVITY_SINGLE_TOP

即singleTop

FLAG_ACTIVITY_CLEAR_TOP

有此标记的Activity在启动时,在其上的所有Activity都将被销毁,一般会和singleTask一同出现,当被启动的Activity是standard模式时,该Activity及以上的Activity都会出栈,再重新创建新的Activity

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

有该标识的Activity将不会出现在历史Activity列表中,xml中等同于:

android:exculdeFromRecents="true"```

#####IntentFliter的匹配规则

- 显式调用

明确表示启动对象的包名类名

- 隐式调用

需要Intent匹配IntentFliter所设置的过滤信息

- 一个Activity可以有多个IntentFliter,一个IntentFliter可以有多个action、category或是data。

- 其中Intent需要同时匹配一个IntentFliter中的三种(action、category和data)信息。

- 一个Activity中只要匹配一个IntentFliter就可以了。

- #####Action

action系统有预定义的,当然我们也能自己定义,其中intent中action必须与IntentFliter中一个action匹配。(没有就默认不匹配)还有一点就是action区分大小写

- #####Category

category系统有预定义的,当然我们也能自己定义。category与action不同的是:intent中没有category是默认匹配成功的。如果intent定义了category,则要求intent中所有的category都是intentFliter的category中的一个。

- #####data

data的匹配模式与action类似,都需要至少一个匹配。

data的语法

android:host="string"

android:port="string"

android:path="string"

android:pathPattern="string"

android:pathPrefix="string"

android:mimeType="string"/>

data由两部分组成,URI和mimeType。URI指定类似于路径的状态,mimeType指定媒体数据

- URI的结构有mimeType前面的scheme、host、port、path、pathPattern、pathPrefix组成。

://:/{||}

对应:

content://com.example.project:200/folder/subfolder/etc

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

- scheme:URI的模式,如http、file、content等,若没有指定scheme,URI是无效的。

- Host:URIde主机名,URI中不能为空

- Port:URI的端口号,scheme和host都指定了才有意义。

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

Path指定完整路径

pathPattern也指定完整路径,但是可以使用通配符"",""表示0或多个字符。由于正则表达式的规范,真实字符串中""要用"\"表示,""要用"\\"表示

pathPrefix表示路径的前缀信息

当没有指定URI时,URI默认为content和file。

Intent添加data信息:

如果要指定完整data信息,需要setDataAndType

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

使用setData和setType会彼此擦除对方的值

这里data比action特殊的还有一点,就是:

...

...

上面的两种方法是一样的。

当我们隐式启动一个Activity的时候,可以做一下判断,看是否能匹配到我们的隐式Intent,如果不做判断没找到对应的Activity系统就会抛出android.content.ActivityNotFoundException异常。

采用PackageManager的resolveActivity方法或者Intent的resolveActivity方法,如果找不到匹配的Activity就会返回null,我们通过判断返回值就可以规避上述错误了。

######接收隐式意图的Activity必须有,这个category的作用在于上述两个方法只要不返回null,就能启动Activity。

######有一类action和category的共同作用是标明这是一个入口Activity,并且会出现在系统的应用列表中,少一个都没有任何意义,也不会出现在系统的应用列表中。

//最先启动的activity

//桌面的图标,显示在程序列表中

####知识点总结的比较全,难听点就是笔记太啰嗦了吧,感觉都有点重要,整章的内容都快要都写进来了。

####这一章的内容不是特别多,但我还是写的有些杂乱,或许写多了,就好了吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值