杨说:Activity知识点总结

1,314

目录

一、Activity存在的意义
二、Activity生命周期
三、创建window,统一管理window
四、分发事件,响应用户操作
五、Activity启动模式,实现自由切换
六、Activity启动流程

一、Activity存在的意义

Activity是Android为开发者提供的一个系统组件,便于开发者开发页面。Activity的主要功能有一下几个方面,

1、Activity生命周期,简化用户创建页面流程
2、创建window,统一管理window
3、分发事件,响应用户操作
4、Activity启动模式,实现自由切换
5、Activity页面间的数据传递

二、Activity生命周期

提到Activity就不的不提它的生命周期,系统通过模板模式将需要复写的方法暴露给开发者,然后开发者可以复写自己的逻辑在固定的方法中。Activity的生命周期有一下几种,他们都是成对出现的

onCreate是在Activity被创建的时候调用的只会调用一次,onDestroy是在Activity被销毁的时候调用
onStart是Activity处在可见但还没获取到焦点时候的会调动可调用多次,onStop是Activity不可见时候的回调 onResume是Activity可见并获取到焦点时的回调,这时可响应与用户的交互。onPause是Activity失去焦点的回调

如果因为内存不足导致Activity被销毁了,用户重新启动这个Activity生命周期会从onCreate开始

Activity意外关闭时会调用onSaveInstanceState我们可以在这里缓存一些数据,然后在Activity恢复的时候调用onRestoreInstanceState用户恢复数据,现在谷歌推出的Jetpack ViewModel也可以实现存储数据和恢复数据的功能,前者是缓存少量数据,后者用户缓存大量数据

onSaveInstanceState 是在onStop之前 Android系统版本大于9.0 在onStop之后,View States用于保存View状态,Instance States用户保存View States和开发者要保存的数据。Android系统会自动保存View的状态。

onRestoreInstanceState 是在onStart之后,开发者不能存储太大量数据,否则会导致在页面重建的时候卡顿。如果需要保存大量数据请使用Jetpack的ViewModle

2.1 常见场景生命周期调用

1、启动Dialog
是不会调用Activity生命周期的,因为不会经过AMS
2、启动一个透明的Activity
A onPause B onCreate onStart onResume
3、启动一个不透明的Activity
A onPause B onCreate onStart onResume A onStop
4、点击home键
onPause onStop

onPause 中不要做耗时的操作,因为会影响后面页面onResume导致卡顿

onStop 应用有可能被系统回收

设置Activity的android:configChanges="orientation|keyboardHidden|screenSize"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法;

不设置执行横竖屏切换执行方法 onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume

2.2 对Activity生命周期的监听

监听Activity生命周期监控可以使用Jetpack的LifeCycle。使用一个隐藏的Fragment和观察者模式监控Activity的生命周期。具体可查看文章 杨说:Jetpack Lifecycle 详解

三、创建window,统一管理window

在Activity启动的时候,会调用生命周期onCreate,在onCreate的我们需要使用setContentView(view)把我们自定义的View设置到Activity管理的window中

这个window是PhoneWindow(每个Activity只有一个Window),PhoneWindow是管理用户自定义的View的类,他的内部是DecorView,我们定义的View是存储在DecorView中,content的位置。PhoneWindow是在Activity调用attach的是时候创建PhoneWindow

PhoneWindow是被WindowManager管理的,在Activity调用attach方法的时候,获取系统的WindowManager然后,根据PhoneWindow创建对应的WindowManagerImpl,而WindowManagerImpl中实际干活的是WindowManagerGlobal,WindowManagerGlobal是单例的管理整个应用所有的window,并提供与WMS通信的IWindowManager接口和IWindowSession接口

调用WindowManager的addView添加DecorView,addView内部会创建ViewRootImpl,然后调用ViewRoot的setView,ViewRootImpl管理和WMS通信,接收输入和Touch事件,负责整个View的通信。

ViewRoot的内部调用requestLayout开始测量客户端要绘制的自定义View,首先要发送异步消息,请求Vsync信号,在收到消息后就开始我们熟悉的measure layout draw

在draw的时候应用端会像SurfaceFlinger申请Surface用于绘制客户端自定义的view,然后提交到SurfaceFlinger,SurfaceFlinger将图像数据合成后提交到FrameBuffer中,然后绘制到手机屏幕上

四、分发用户点击事件,响应用户操作

用户输入或者点击屏幕的时候会把event事件存储在/dev/input/eventXX的一个FD上

SystemService进程中有两个线程用于处理input事件

InputReader线程用于读取event
1、使用inotify监听fd的增加或者删除
2、使用epoll机制监听fd更改,处理Rawevent成KeyEvent、MotionEvent、TrackEvent
3、把event事件分发给InputDispather线程,应为在同一个进程所以可以直接添加到event队列中

InputDispatcher线程用于分发event 根据当前设备的状况来优先消化事件(该过程交由PhoneWindowManager.java来处理.最后,剩余事件分发给ViewRoot;ViewRoot再分发给IME输入法或View、Activity。
1、使用epoll机制等待event事件
2、InputChannel使用socket机制,将event事件发送给App进程

App进程
1、View的注册过程
每一个window有一个InputChannel对应一个Socket,InputChannel是在ViewRootImpl setView的时候创建的,同时也创建了时间接收的类WindowInputEventReceiver,addWindows时向WMS注册InputChannel用于接收event事件,WMS通过IM注册,IMS在向InputDispatcher注册,这样在收到event事件后就能想App进程转发event了

2、event事件接收
event事件发送过来第一个接收到的是InputEventReceiver的dispatchInputEvent方法,调用WindowInputEventReceiver onInputEvent,通过Handler发送input事件,使用责任链处理input事件,如果处理完通知systemService进程

3、event事件处理 event事件被调用WindowInputEventReceiver收到消息 event -> Hanlder -> DecorView -> PhoneWindow -> Activity, Activity -> PhoneWindow -> DecorView -> ViewGroup -> View

ViewGroup中分发
分发流程
dispatchTouchEvent -> onInterceptTouchEvent
处理流程
-> onTouch -> onTouchEvent -> onClick

五、Activity启动模式,实现页面自由切换

5.1 管理类

ActivityRecord 是AMS用于管理App进程Activity的对象
TaskStack 是管理多个ActivityRecord的栈,栈顶的Activity表示获得焦点的Activity
ActivityStack 是管理多个TaskStack的栈,栈顶的TaskStack表示获取焦点的任务
ActivityStackSupervisior 管理多个ActivityStack,只有一个ActivityStack获取到焦点

5.2 Activity启动模式

1、standard 标准模式直接在TaskStack栈顶创建Activity对象
2、singleTop 如果要启动的Activity在TaskStack栈顶的话,不需要创建Activity,调动onNewIntent onResume,否则就创建一个Activity对象
3、singleTask 如果要启动的Activity在TaskStack栈中存在,将它上面的所有对象出栈,调用onNewIntent onResume,否则就创建一个Activity对象。singleTask模式下,任务取决于清单中配置的taskAffinity
4、singleInstance 启动Activity单独存在在一个TaskStack栈中,并整个应用只有一个这个对象

5.3 设置启动模式

1、在xml中声明android:launchMode
2、使用Intent启动
FLAG_ACTIVITY_NEW_TASK 类似singleTask当在清单中为Activity设置taskAffinity属性时,能跳转到指定任务,任务不存在创建任务
FLAG_ACTIVITY_SINGLE_TOP singleTop模式
FLAG_ACTIVITY_CLEAR_TOP 类似singleTask,当Activity存在任务中,TaskStack都会出栈,从新创建入栈
FLAG_ACTIVITY_NO_HISTORY 被指定的 Activity 在跳转到其他 Activity 后,将从任务中移除
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 指定Activity不出现在最近应用列表中

5.4 与任务关联

taskAffinity 可指定Activity要关联的任务,默认情况任务名为包名
属性allowTaskReparenting = true 可以让改Activity从一个任务回签到taskAffinity指定的任务

六、Activity启动流程

6.1 启动App的进程

无论是从Context还是Activity启动一个Activity都是调用startActivy,最后调用到Instrumentation的exeStartActivty,通过Binder通知AMS开始做Activity的启动的准备工作,在这里可以Hook Instrumentation实现对启动的Activity的拦截

6.2 AMS准备工作

SystemService进程AMS
1、PMS检测Activity是否存储
2、创建ActivityRecord记录Activity的所有信息
3、创建Token记录视图是否可以显示,通知WMS创建AppWindowToken
4、根据启动模式创建TaskStack
5、检测启动的进程是否存在,检测ProcessRecord ApplicationThread
6、如果不存在进程将ActivityTread作为参数通过socket通信传递给Zygote,开始fork进程

6.3 App进程启动

6.3.1 native层 启动Binder

1、open Binder 打开Binder驱动
2、mmap 内存映射
3、注册线程到Binder驱动

6.3.2 java层

执行ActivityThread main函数 1、Looper.prepareMainLooper 准备主线程 2、创建ActivityThread 3、attach 通知AMS进程创建成功,进行备案 4、Looper.loop 主线程Looper启动

6.4 AMS收到App进程启动消息

赋值ProcessRecord,ApplicationThread,通知App SystemService已经备案成功

6.5 App收到AMS备案成功消息

1、反射Application,关联Context
2、调用attachBaseContext
3、创建ContentProvider 4、调用onCreate

6.6 启动Activity

AMS scheduleLaunchActivity调用启动Activity App进程
1、创建ActivityRecordClient
2、performLaunchActivity
反射创建Activity关联Context
调用attach 创建PhoneWindow 创建WindowManager 关联Window.callback
3、调用onCreate setContentView设置自定义View
4、调用onResume 执行绘制视图流程

参考

1、Android官方文档
2、小专栏《重学安卓》
3、Android篇:2019初中级Android开发社招面试解答(上)