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;
 
Instrumentation.newActivity 创建成功--执行Activity的生命周期。
 

总结: 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里面。

 

posted @ 2022-02-26 16:20  向着内核前进!  阅读(437)  评论(0编辑  收藏  举报