Android面试——Activity篇
一: Activity的启动流程
第一种:跨进程启动(以从桌面点击应用图标启动应用为例)
由Launcher进程通过Binder向SystemServer进程发起startActivity请求;
SystemServer进程收到请求后,向Zygote进程发起创建进程的请求;
Zygote进程fork出子进程,即新的APP进程;
APP进程通过Binder向SystemServer进程发起attachApplication的请求;
SystemServer进程收到请求,经过处理后,通过Binder 向APP进程发送scheduleLaunchActivity请求;
APP进程的ApplicationThread收到请求后,通过handler向主线程发送LAUNCH_ACTIVITY消息;
主线程在收到Message后,通过反射机制创建目标Activity,并回调Activity.onCreate()方法;
第二种:进程内启动
Activity.startActivity() 经过处理 交给Instrumentation.execStartActivity()执行;
然后会通过Binder机制 与AMS 通信,向SystemServer进程的AMS 发送 启动Activity的请求,这里通过ActivityManager.getService().startActivity,ActivityManager.getService()获取的是AMS的代理对象;
ActivityManagerService.startActivity--->ActivityStarter.startActivityUnchecked ---> 通过AplicationThread的代理类去让ApplicationThread执行这个请求;
ApplicationThread又会通过Handler
让ActivityThread去执行startActivity;总结: AMS 通过IApplicationThread的AIDL接口来使ApplicationThread去真正的执行我们的创建过程。
二:Activity的生命周期
onCreate() 与 onDestory()表示 一个Activity的创建和销毁;
onStart() 与 onStop()表示 可见 与 不可见;
onResume() 与 onPause() 表示进入前台获得焦点与 退出前台失去焦点,也表示 可交互 与 不可交互;
onRestart() 表示重新启动;
onCreate():初始化一些资源,以及加载全局数据
onStart():加载一些Activity可见时才需要加载的数据
onRusume():轻量级的数据加载,数据变动只在onRusume--onPause()之间
onPause():不可进行太耗时的操作或者重量级的释放操作,因为这会影响下一个Activity进入前台与用户交互,只有当前onPause方法执行完毕,下一个Activity的onStart才会调用;并且程序突然死亡时只有onPause一定会调用,因此可以在这个方法里进行持久化关键数据
onStop与onDestory:释放资源
三: Activity的任务栈和启动模式
任务栈:每次打开或者退出Activity的时候都会在一个被称为任务栈的结构中添加或者减少一个Activity组件,一个任务栈包含了一个activity的集合;
相关类:ActivityRecord、TaskRecord、ActivityStack,ActivityStackSupervisor,ProcessRecord
启动模式:
Standard:默认,每次启动Activity都会创建一个新实例
SingleTop:如果要启动的Activity已经在栈顶,则不会重新创建Activity,只会调用该该Activity的onNewIntent()方法;如果要启动的Activity不在栈顶,则会重新创建该Activity的实例。
SingleTask:如果要启动的Activity已经存在于它想要归属的栈中,那么不会创建该Activity实例,将栈中位于该Activity上的所有的Activity出栈,同时该Activity的onNewIntent()方法会被调用。
SingleInstance:要创建在一个新栈,然后创建该Activity实例并压入新栈中,新栈中会且仅会存在这一个Activity实例。并且全局复用;
四:onSaveInstanceState(),onRestoreInstanceState的调用时机
onSaveInstanceState(Bundle outState):
1. 从最近任务中运行其他程序
2. 当用户按下Home键
3. 屏幕方向切换
4. 按下电源键
5. 从当前Activity启动一个新的Activity
onRestoreInstanceState:只有在Activity确实被系统回收后,重建Activity时才会被调用
1. 屏幕方向切换时
2. 在后台被回收
五:Activity之间传递数据的方式
Intent,全局变量,SharedPreferences,数据库,文件
六:Activity之间传递数据方式中Intent是否有大小限制,传递数据偏大的解决方案?
首先:传递的过程是startActivity->startActivityForResult->Instrumentation.execStartActivity->ActivityManger.getService().startActivity
intent携带的数据要从APP进程传输到AMS进程,再由AMS进程传递到目标Activity所在进程;
其次:Binder驱动在内核中创建的数据缓存区,数据需要存放在这个区里面,而binder内存大小不到1M;
结局方案:
非IPC:单例,eventBus,Application,sqlite、shared preference、file
IPC:共享内存性能不错,Socket或者管道性能不好,涉及两次拷贝;
七:onNewIntent()方法什么时候执行
第一种:IntentActivity处于任务栈的顶端,但是处于onPause,onStop状态,其他应用发送Intent,会执行 onNewIntent,onRestart,onStart,onResume
第二种:Activity A 已经启动过,处于当前应用的Activity堆栈中,
当A的启动模式为 SingleTop,A在栈顶时要再启动A;
当A的启动模式为SingleInstance,SingleTask,如果A已经在堆栈中,再次启动会调用onNewIntent()
八: Activity的显式启动和隐式启动
显式启动:
1. 构造方法传入Component
2. setComponent( componentname)
3. setClass/setClassName
隐式启动:
通过Intent,通过AndroidManifest.xml中设置action,data,category,让系统筛选中合适的Activity;
九:Intent-filter 的匹配规则
1. action
至少包含一个action,intent中的action只要与其中一条匹配成功即可且Intent中action最多只有一条
2. category
至少包含一个category,android:name为android.intent.category.DEFAULT
ntent-filter中,category可以有多条
intent中,category也可以有多条
intent中所有的category都可以在intent-filter中找到一样的(包括大小写)才算匹配成功
3. data
intent-filter中可以设置多个data,可以不设置data;
intent中只能设置一个data
intent-filter中指定了data,intent中就要指定其中的一个data
十:onCreate和onRestoreInstance方法中恢复数据时的区别
1. onCreate()中的参数Bundle 可能为空,所以要做非空判断;onRestoreInstanceState的Bundle参数一定不会是空值
2. onRestoreInstance 不一定会被调用,它只有在Activity被回收了才会调用
十一:跨App启动Activity的方式,注意事项
1. 通过Intent 隐式启动时,如果有多个action值相同的Activity,系统会让你选择启动哪个,解决办法时通过指定Intent-filter的 data属性,Intent 则要加上一个URI,该URI的scheme必须与data的scheme相同;
2. 共享UID的APP:
UID:Android使用UID来标识一个应用程序,UID在应用安装时分配,并且不会改变,一个程序只能有一个UID,多个应用可以使用shareduserID共享同一个UID,前提是这些应用的签名要相同;
3. 使用exported
一旦设置了intentFilter之后,exported就默认被设置为true了
在Manifest中添加exported属性
4. 如何防止自己的Activity被外部非正常启动
给自己的Activity 添加android:permission=”xxx.xxx.xx”,那么想要访问你的Activity就必须声明uses-permission xxx.xxx.xx
十二: Activity的任务栈是什么
即Task,栈结构,存放Activity;退出应用程序时只有将所有任务栈找那个的所有Activity出栈,任务栈才能销毁,
任务栈可以移动到后台,在其中保留每一个Activity的状态
对应的类:ActivityRecord、TaskRecord、ActivityStack
十三: Activity的常用标记位
FLAG_ACTIVITY_NEW_TASK:指定启动模式为SingleTask
FLAG_ACTIVITY_SINGLE_TOP:指定启动模式为SingleTop
FLAG_ACTIVITY_CLEAR_TOP:一般与SingleTask启动模式一起出现,启动时位于它上方的Activity出栈,如果被启动的Activity实例已存在,系统则会调用它的onNewIntent;
12. Activity的数据是怎么保存的,进程被Kill后,保存的数据怎么恢复的
首先,回调onSaveInstanceState, 将数据保存到 outState中,也就是ActivityClientRecord的state,
ActivityClientRecord实例,都存放在ActivityThread的mActivities里面Activity变得不可见时(onSaveInstanceState和onStop回调之后),在应用进程这边会通过ActivityTaskManagerService的activityStopped方法,把刚刚在onSaveInstanceState中满载了数据的Bundle对象,传到系统服务进程那边! 然后(在系统服务进程这边),会进一步将这个Bundle对象,赋值到对应ActivityRecord的icicle上
ActivityRecord是用来记录对应Activity的各种信息的,如theme,启动模式、当前是否可见等等(为了排版更简洁,上图只列出来一个icicle),它里面还有很多管理Activity状态的相关方法
TaskRecord就是大家耳熟能详的任务栈(从上图可以看出并不真的是栈)了,它的主要职责就是管理ActivityRecord。每当Activity启动时,会先找到合适的TaskRecord(或创建新实例),然后将该Activity所对应的ActivityRecord添加到TaskRecord的mActivities中;
ActivityStack管理着TaskRecord,当新TaskRecord被创建后,会被添加到它mTaskHistory里面。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!