android体系复习---Activity
一、什么是Activity
Activity是与用户交互的入口点。它表示拥有界面的单个屏幕。例如,电子邮件应用可能有一个显示新电子邮件列表的 Activity、一个用于撰写电子邮件的 Activity 以及一个用于阅读电子邮件的 Activity。尽管这些 Activity 通过协作在电子邮件应用中形成一种紧密结合的用户体验,但每个 Activity 都独立于其他 Activity 而存在。因此,其他应用可以启动其中任何一个 Activity(如果电子邮件应用允许)。例如,相机应用可以启动电子邮件应用内用于撰写新电子邮件的 Activity,以便用户共享图片。
二、 生命周期
imageOnCreate:您必须实现此回调,它会在系统首次创建 Activity 时触发。Activity 会在创建后进入“已创建”状态。在 onCreate()方法中,您需执行基本应用启动逻辑,该逻辑在 Activity 的整个生命周期中只应发生一次。
onStart: 当 Activity 进入“已开始”状态时,系统会调用此回调。onStart()调用使 Activity 对用户可见,因为应用会为 Activity 进入前台并支持互动做准备。例如,应用通过此方法来初始化维护界面的代码。
onResume: Activity 会在进入“已恢复”状态时来到前台,然后系统调用 onResume回调。这是应用与用户互动的状态。应用会一直保持这种状态,直到某些事件发生,让焦点远离应用。此类事件包括接到来电、用户导航到另一个 Activity,或设备屏幕关闭。
onPause: 系统将此方法视为用户将要离开您的 Activity 的第一个标志(尽管这并不总是意味着 Activity 会被销毁);此方法表示 Activity 不再位于前台(尽管在用户处于多窗口模式时 Activity 仍然可见)。
onStop: 如果您的 Activity 不再对用户可见,说明其已进入“已停止”状态,因此系统将调用 onStop() 回调
onDestory: Activity即将被销毁,可以做一些工作和资源的回收(Service、BroadCastReceiver、Map、Bitmap回收等)
onRestart: Activity正在重新启动,一般时当前Activity从不可见到可见状态时会执行这个方法,例如:用户按下Home键(锁屏)或者打开新Activity再返回这个Activity
状态保持相关生命周期
onSaveInstanceState: onSaveInstanceState方法在Activity可能被销毁之前执行,保存状态信息,异常销毁后可以利用这些信息进行恢复。【这里的可能被销毁的操作比如,按下home键,或者打开一个新的Activity,都会被执行,因为这些操作如果放置时间过长,则之前的Activity则有可能被销毁。另外屏幕切换时也会调用该方法】
onRestoreInstanceState: 只有在activity确实是被系统回收,重新创建activity的情况下才会被调用,此时参数savedInstanceState一定不为null,在onStart方法之后执行
配置改变触发的生命周期
onConfigurationChanged: 当在清单文件中配置了configChanges时,如果设备发生一些配置变化,则会触发改变。
常见的配置改变:
- orientation:方向变化
- screenSize:屏幕尺寸变化
- keyboardHidden:键盘隐藏
生命周期相关面试题:
- A Activity 打开 B Activity 时都有哪些生命周期回调?
A.onPause -> B.onCreate ->B.onStart -> B.onResume -> A.onStop - 界面旋转的生命周期
onPause -> onStop -> onSaveInstanceState -> onDestroy -> onCreate ->onStart -> onRestoreInstanceState -> onResume
三、 启动模式
启动默认分四种,我们在清单文件中设置launchMode属性配置即可,具体默认如下:
Standard模式: Android的默认启动模式,你不在配置文件中做任何设置,那么这个Activity就是standard模式,这种模式下,Activity可以有多个实例,每次启动Activity,无论任务栈中是否已经有这个Activity的实例,系统都会创建一个新的Activity实例
singleTop: 栈顶复用模式,如果要开启的activity在任务栈的顶部已经存在,就不会创建新的实例,而是调用 onNewIntent() 方法;
应用场景:在通知栏点击收到的通知,然后需要启动一个Activity,这个Activity就可以用singleTop,否则每次点击都会新建一个Activity
singleTask: 栈内复用模式,activity只会在任务栈里面存在一个实例。如果要激活的activity,在任务栈里面已经存在,就不会创建新的activity,而是复用这个已经存在的activity,调用 onNewIntent()方法,并且清空这个activity任务栈上面所有的activity。
应用场景:应用场景:App的主页。
singleInstance:在一个新栈中创建该 Activity 的实例,并让多个应用共享该栈中的该 Activity 实例。一旦该模式的 Activity 实例已经存在于某个栈中,任何应用再激活该 Activity 时都会重用该栈中的实例,是的,依然是调用 onNewIntent() 方法。其效果相当于多个应用共享一个应用,不管是谁激活,该 Activity 都会进入同一个应用中。但值得引起注意的是:singleInstance 不要用于中间页面,如果用户中间页面,跳转会出现很难受的问题。 这个在实际开发中我暂未遇到过,不过 Android 系统的来电页面,多次来电均是使用的同一个 Activity 。
除了在清单文件中配置,我们还可以在代码中设置,且优先级比清单文件中要高
通过设置 Intent.setFlags(int flags) 来设置启动的 Activity 的启动模式。
-
FLAG_ACTIVITY_NEW_TASK
这个标识会使新启动的 Activity 独立创建一个 Task。 -
FLAG_ACTIVITY_CLEAR_TOP
这个标识会使新启动的 Activity 检查是否存在于 Task 中,如果存在则清除其之上的 Activity,使它获得焦点,并不重新实例化一个 Activity,一般结合 FLAG_ACTIVITY_NEW_TASK 一起使用。 -
FLAG_ACTIVITY_SINGLE_TOP
等同于在 launcherMode 属性设置为 singleTop。
四、启动Activity的其他方式
1. 隐式action调用: 在清单文件配置action(必须具有一个DEFAULT的Category)的名字,然后创建intent设置action即可,代码如下:
配置
<intent-filter>
<action android:name="customActionName"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
跳转
val intent = Intent()
intent.action = "customActionName"
context.startActivity(intent)
注意:隐式调用如果找不到action会发生崩溃,在开发中我们可以通过PackageManager的ResolveActivity方法来进行判断,若找不到匹配的Activity会返回一个null。
2. scheme协议:
URL Schema协议格式:
- Scheme:代表该Schema 协议名称
- host:代表Schema作用于哪个地址域
- path: 代表Schema指定的页面,注意要有斜杠
配置
<activity
android:name=".ui.activity.WebViewActivity">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="custom"/>
<data android:host="www.custom.test"/>
<data android:path="/page1"/>
</intent-filter>
</activity>
跳转: 跳转时可以传递参数,跟get请求格式一样即可
val intent = Intent(Intent.ACTION_VIEW,Uri.parse("custom://www.custom.test/page1?arg=yangxiaoliu"))
context.startActivity(intent)
获取参数
val queryParameter = intent.data?.getQueryParameter("arg")
toast(queryParameter!!)
五、Activity启动流程
用户在launch程序里点击应用图标,会通知ActivityManageService启动应用入口的Activity,ActivityManageService发现这个应用还未启动,则会通知Zygote进程孵化出应用进程,然后这个dalvik应用进程里执行ActivityThread的main方法。应用进程接下来通知ActivityManageService应用进程已启动,AMS保存应用进程的一个代理对象,这样AMS可以通过这个代理对象控制应用进程,然后AMS通知应用进程创建入口Activity的实例,并执行它的生命周期方法。
详细启动流程可参考该博客
http://www.cloudchou.com/android/post-788.html
六、Activity与window、View之间的关系
我们可以追踪Activity的setContentView方法来了解他们三个的关系,源码比较简单,这里只用文字梳理下流程。
每个Activity中都持有一个Window对象,我们在onCreate中setContentView其实最终会调用Window的setContentView方法,而Window对象则是在Activity的onAttach方法中进行的实例化,实例化对象是PhoneWindow。PhoneWindow的setContentView方法则把View添加到了DecorView中的id为R.id.content的mContentParent中。
下面这张图可以简单反应出他们的关系
image.png