一 activity 是什么
问题:什么是Activity
答:Activity 在中文的意思是活动,它是与用户进行交互的载体,接受用户的行为事件,如:点击,触摸,长按,滑动等操作,并进行处理,显示相应内容。
二 activity 生命周期
01 activity 的4中状态
1 running
此时 activity处于栈顶,是一个活动状态,可见,能正常接收用户的行为事件。
2 paused
此时 acitivty 处于可见,但是失去焦点的状态。正常保存 activity 的信息和成员变量,但是当内存紧张的时,可能会被回收
3 stopped
此时 activity 处于不可见,失去焦点的状态。在内存不紧张的时候会正常保存 activity 的信息及成员变量。但是当内存紧张时,会被回收。
4 killed
此时 activity 已经被系统回收。
02 activity 生命周期分析
1 生命周期简介
onCreate
activity 生命周期中第一个方法,当activity被创建的时候调用。我们常见的操作是,通过setContentView方法设置布局。然后进行数据的预处理。
onRestart
这个方法在 activity 生命周期中不一定会被调用。只有当 activity 处理后台。我们重新点击图标时,activity 重新启动,这个方法才会被调用。
onStart
这个方法在 activity 启动的时候会被调用,此时 activity 处于可见状态,但是没有获取焦点。不能接受用户的行为事件。
onResume
这个方法被调用时,表示此时 activity 处于可见并且获取了焦点,可以接受用户行为事件。我们可以在这个方法中,进行资源的初始化。
onPause
当这个方法被调用时,表示此时 activity 处于可见,但是失去焦点的状态,不能接受用户行为事件。与onResume方法对应。
onStop
当这个方法被调用时,activity 处于后台状态,不可见,失去焦点,不能接受用户行为事件。如果此时内存紧张,该 activity 会执行 onDestory 方法,被系统回收。
onDestory
生命周期最后一个方法,当这个方法被调用的时候,表示 activity 会被销毁,被系统回收。在这个方法中,我们可以做一些,回收工作和资源的释放。
2 场景分析
activity 启动:
graph LR
onCreate-->onStart
onStart-->onResume
当点击 Home 键回到主界面:
graph LR
onPause-->onStoped
当点击应用图标,再次回到 activity :
graph LR
onRestart-->onStart
onStart-->onResume
当退出 activity 时:
graph LR
onPause-->onStop
onStop-->onDestory
3 异常情况下的场景分析
异常情况下的生命周期是指:Activity被系统回收或者由于当前设备的Configuration发生改变从而导致Activity被销毁重建。
① 资源相关的系统配置发生改变导致Activity被杀死并重建
横竖屏切换导致系统配置发生变化,默认情况下,系统配置发生变后,Activity就会被销毁并重新创建,生命周期如下:Activity—系统配置发生变化→onSaveInstanceState→onPause→onStop→onDestroy—重新创建→onCreate→onStart→onRestoreInstanceState→onResume
当系统配置发生改变后,Activity会被重建。我们可以通过一些属性,在系统配置改变时不重建Activity,比如可以指定Activity的configChanges属性,将值设置为orientation,那么横屏时不重建Activity
② 资源内存不足导致低优先级的Activity被杀死
当系统资源内存不足时,会根据Activity的优先级杀死Activity,由低到高。Activity的优先级分为三种:
a:前台Activity:正在和用户交互的Activity,优先级最高
b:可见非前台的Activity:比如Activity中弹出一个对话框,导致Activity可见但是位于后台无法与用户交互
c:后台Activity:已经被暂停的Activity,比如执行了onStop方法,优先级最低。
系统会按照上述优先级去杀死目标Activity所在的进程,并通过onSaveInstanceState和onRestoreInstanceState方法存储和恢复数据。如果一个进程中没有四大组件在执行,那么这个进程将会很快被系统杀死。因此一些后台工作不适合脱离四大组件而独自运行在后台中,这样进程容易被杀死。比较好的方式是将后台工作放在Service中进行从而保证进程有一定的优先级。
03 android 进程优先级
前台/可见/服务/后台/空
前台:一般情况就是正在和用户交互的 activity 或者与 activity 绑定的 service,所在的进程叫前台进程。
可见:处于前台,但是用户无法点击的状态的 activity ,所在的进程。
服务:后台开启的服务所在的进程,叫服务进程。
后台:处于前台进程时,由于点击了 home 键进如后台的 activity 所在的进程。
空:没有活跃的组件,处于缓存目的保存的 activity,所在的进程,叫空进程
三 activity 任务栈
01 android任务栈又称为Task,它是一个栈结构,具有后进先出的特性,用于存放我们的Activity组件。
02 我们每次打开一个新的Activity或者退出当前Activity都会在一个称为任务栈的结构中添加或者减少一个Activity组件,因此一个任务栈包含了一个activity的集合, android系统可以通过Task有序地管理每个 activity,并决定哪个Activity与用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。
03 在我们退出应用程序时,必须把所有的任务栈中所有的activity清除出栈时,任务栈才会被销毁。当然任务栈也可以移动到后台, 并且保留了每一个activity的状态. 可以有序的给用户列出它们的任务, 同时也不会丢失Activity的状态信息。
04 需要注意的是,一个App中可能不止一个任务栈,某些特殊情况下,单独一个Actvity可以独享一个任务栈。还有一点就是一个Task中的Actvity可以来自不同的App,同一个App的Activity也可能不在一个Task中。(举个例子,当A应用的A页面启动了B应用的B页面,如果此时B页面是标注模式那么此时B页面会进入A页面所在的栈。那么此时A应用的A页面和B应用的B页面存在一个栈中。重点来了:如果此时,用户home键回到桌面打开了B应用,那么此时B页面会立刻马上回到B应用开启的新栈中。)
05 默认情况下栈的名字和应用的包名一样,通过 taskAffinity属性可以为Activity选在想要存放的栈。
06 启动一个应用(不是启动一个页面),系统就会寻找或者创建一个栈名为该应用包名的栈 ,默认情况下,栈名即是包名,来放置根Activity
07 按back键回退时,Activity后进先出,系统存在的栈也会按一定规则回退
四 activity 启动模式
01 启动模式介绍
1 standard
标准模式,这也是系统默认的启动模式。每次启动一个 activity 都会生成一个新的实例,并把它压入栈顶。不管这个 activity 是否存在,这是一种典型的多实例实现。一个任务栈中可以有多个实例,这些实例可以存在不同的任务栈中。这种情况下,谁启动了这个 activity ,这个 activity 就会运行在启动它的那个 activity 所属的任务栈中。
2 singleTop
栈顶复用模式,顾名思义,栈顶复用就是只有当任务栈的顶部刚好是需要启动的 activity 时,这个 activity 会被复用,不需要再生成新的实例。同时它的onNewIntent方法会被回调,通过此方法参数我们可以读取当前请求信息。如果处于栈顶的 activity 不是需要启动的 activity 则和标准模式情况相同。
3 singleTask
栈内复用模式,当启动此模式的 activity 时,如果栈内存在此实例,就不会创建新实例,但是会重新调用onNewIntent,通过此方法参数我们可以读取当前请求信息。具体就是:系统会检查是否存在此 activity 所需要的栈,如果不存在这样的栈,就会创建这样的栈,生成 activity 的实例放入栈中;如果存在这样的栈,就会检查栈内是否存在 activity 的实例,如果存在 activity 的实例,就会将此 activity 上面的activity 进行销毁。让此 activity 处于栈顶。如果不存在此 activity 就会生成实例放入栈顶。
4 singleInstance
单实例模式,这是加强的 singleTask 。具有 singleTask 所有特点,加强的地方是:具有这种模式的 activity 只会单独的位于一个任务栈中,这个任务栈中只会有且只有一个实例。除非这个任务栈被销毁,不然不会重新生成实例。
02 设置启动模式
1 xml方式
在 activity 注册的时候设置。但是此方式不能指定为 FLAG_ACTIVITY_CLEAR_TOP。(也就是说,需要在Intent.addFlags中动态选择是否实现这种效果)
2 Intent方式
用 Intent.addFlags 方法设置,但是此方法不能指定为 singleInstance。
五 activity 页面跳转
问:什么是 scheme 跳转协议
答:Android 中的 scheme 是一种页面内的跳转协议。通过定制自己的 shceme 可以方便的 app 里进行页面间跳转。通过 scheme 服务器可以定制化的告诉 app 需要跳转到哪个页面,可以通过通知栏消息定制跳转的页面,可以通过 H5 跳转页面。
01 页面的跳转方式
1 显示调用
显示调用需要明确指定被启动对象的组件信息,包括包名和类名。
2 隐式调用
隐式调用则不需要指定被启动组件的信息。
3 总结
原则上 一个Intent不能及时显式调用又是隐式调用,如果二者都存在,则以显式调用为主。
02 隐式调用时的匹配规则
IntentFilter 就是为隐式调用提供匹配规则的。在隐式调用过程中Intent不能匹配目标组件中IntentFilter所设置的过滤信息。则无法启动目标Activity。IntentFilter中的顾虑信息有 action category data 。下面是一个过滤规则的示例:
<activity
android:name=".SecondActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="com.jack.charpter_1.c" />
<action android:name="com.jack.charpter_1.d" />
<category android:name="com.jack.category.c" />
<category android:name="com.jack.category.d" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
可以清楚的看到,一个匹配规则过滤列表中的 action category data 有多个。只有一个Intent同时匹配任意一个action 所有category 任意一个data时,才能匹配成功。
1 action 匹配规则
action 是一个字符串,系统预定义了一些 action ,同时我们也可以在应用中定义自己的 action 。action 的匹配规则是 Intent 中的 action 必须能够和过滤规则中的 action 匹配,这里说的是指 action 的字符串值完全一样。一个过滤规则中可以有多个 action ,那么只要 Intent 中必须有 action 能够和和过滤规则中的任意一个 action 相同即可匹配成功。
2 category 的匹配规则
category 是一个字符串,系统预定义了一些 category ,同时我们也可以在应用中定义自己的 category 。category的匹配规则和 action 不同。它要求 Intent 中出现的所有 category 在过滤规则中都必须存在。当然 Intent 中也可以没有 category ,如果没有 category 的话,按照上述规则任然可以匹配成功。如果不设置 category ,系统会默认为我们的 Intent 设置一个 “android.intent.category.DEFAULT”这个 category ,为了我们的 Activity 能够接受隐式调用,就必须在 Intent-Filter 中指定“android.intent.category.DEFAULT”这个category。
3 data 匹配规则
data 结构语法:
<data
android:mimeType="string"
android:scheme="string"
android:host="string"
android:port="8080"
android:path="/string"
android:pathPrefix="/string"
android:pathPattern="string" />
可以清楚看到 data 由两部分组成,mimeType 和 URI 。mimeType 指媒体类型,比如 image/jpeg andio/mpeg4-generic 和 video/* 等。可以表示 图片 文本 视频等不同的媒体格式,而URI 是统一资源标识符。data 匹配规则:和 action 类似,如果规则中定义了 data ,那么 Intent中必须含有 data 数据,并且 data 数据能够 完全匹配规则中的某一个 data。这里的完全匹配是指 规则中出现的 data 部分,也出现在 Intent 的 data 中。