面试八股文记录(一)-Android
jetpack
Google推出的现代化Android开发组件库集合,统一兼容Android各个版本,解决碎片化,内存泄漏,生命周期管理,代码冗余等问题
统一开发范式 MVVM,支持Kotlin协程,Flow,Compose现代开发方式
四大分类:
架构组件
1、viewmodel
2、LiveData/StateFlow/SharedFlow
3、Lifecycle
4、Room数据库,SQLite封装ORM框架,替代原生SQLite
5、DataStore:轻量本地存储,替代SharedPreferences
6、Paging:分页式加载框架,处理海量列表,可以自动分页、预加载、加载状态,适配RecycleView/Compose LazyList
7、Navigation导航:统一页面跳转管理,替代Intent跳转
8、WorkManager:后台任务调度
UI组件
1、Compose
2、AppCompat
3、Material Components
4、COnstraintLayout
5、Fragment
6、View Binding:自动生成控件绑定类,替代findviewbyid / Data Binding:支持xml直接绑定数据,表达式,MVVM双向绑定
7、WindowManager:适配折叠屏,大屏,多窗口设备
基础工具组件
1、Core KTX:给原生API扩展kotlin语法糖
2、Annotations:注解
3、Multidex:方法数超过65536的分包方案
4、Startup:应用初始化框架,替代ContentProvider启动,优化冷启动速度
行为组件-系统权限,媒体,安全
1、Permissions:简化动态权限申请,封装授权回调,判断权限状态
2、Media3:音视频播放器
3、Security:加密存储密钥,文件加密,适配不同系统加密方案
4、Biometric:生物识别
5、SplashScreen:统一标准启动页,替代自定义闪屏,优化冷启动体验
核心优势:
1、版本兼容,全部组件通过androidx.*包名,最低可兼容API14,不用写大量版本判断
2、生命周期安全:Lifecycle体系杜绝大量的内存泄露:组件可以自动感知页面生命周期状态,页面销毁时自动取消订阅
四大组件
1、Activity:
负责跟用户交互的界面组件,一个activity通常对应一个屏幕页面,核心是生命周期的管理,oncreate初始化,onstart可见,onresume可交互,onpause部分可见,onstop不可见,ondestroy页面销毁,他还有四种启动模式-standard,singletop,singtask,singleinstance,决定了activity如何实例化和压栈的
2、Service
用于执行后台长时间运行的任务,启动方式分为两种
startService:启动后一直运行,直到主动调用停止
bindService:提供客户端-服务器模式,当所有绑定者解绑后服务自动销毁,需要注意的是,Service默认再主线程,耗时操作需要另外开子线程,否则可能ANR
3、BroadcastReceiver
广播接收器,用来接收系统或应用发出的广播,如开机完成,网络变化等,注册方式有静态注册 Manifest中声明和动态注册 (代码中registerReceiver)。动态注册需要在合适的生命周期中去注册和反注册,比如onresume和onpause,防止内存泄漏或者崩溃。onReceive方法运行在主线程,不能耗时操作,也不可以直接弹窗。通常用于启动service或发送通知,进程内通信现在更倾向于LiveData或Flow来代替
4、ContentProvider
为应用间数据共享提供标准接口,底层可以是SQLite,文件等。外部应用通过ContentResolver配合URI进行CRUD操作,系统通过他来管理联系人,媒体库等,需要在manifest中注册,可以精细控制读写能力,保证数据安全。
这四个组件大多用Intent交互
四大启动模式
1、standard 标准模式
默认模式
2、singTop 栈顶复用模式
系统会判断要启动的activity是否在目标栈的栈顶,如果在就不建立新实例,而是调用他的onnewIntent方法复用现有实例;如果不在栈顶就新建,适合那些被重复打开,又不希望栈顶出现相同连续页面的场景
3、singleTask 栈内复用模式
整个栈内只存在一个实例,启动时,会先检测目标任务栈里是否已经有该activity实例了,如果没有就新建并放入栈中;如果有,会把该实例上面的所有activity全部出栈,让这个实例重新置于栈顶,并调用onNewIntent,通常用来做主页面
4、singleInstance 全局单例模式
是singleTask加强版,不仅栈内唯一,而且这个activity独占一个任务栈,不允许有其他activity,无论从哪个任务栈启动,它都会在一个独立的任务栈中。场景为:来电界面,闹钟提醒。
这些启动方式设置除了用manifest中硬编码设置launchMode外,还可以用Intent的FLAG_ACTIVITY_SINGLE_TOP,FLAG_ACTIVITY_NEW_TASK等来动态覆盖行为。
谈谈对Handler的了解和看法
handler的话是Android中非常重要的消息机制,主要用于线程间的通信,他主要是靠四个角色来一起协同工作的:
Handler:发送和接受消息入口,sendMessage/post最终都走到enqueueMessage将消息放入队列中去
MessageQueue:存储消息,单链表实现的优先级队列
Looper:死循环从MessageQueue中去消息,然后发给对应的Handler的dispatchMessage
Message:消息载体,内部可以用obtain回收复用,避免频繁创建对象
运行流程:
1、线程创建Looper:调用Looper.prepare()创建本线程唯一Looper实例,同时会初始化一个MessageQueue,然后调用Looper.loop()开始无限循环
2、handler发送消息:创建Handler时会绑定当前线程的Looper,Handler发出的消息携带targe会指向自身,进入Looper对应的MessageQueue
3、消息分发:Looper的loop()中,queue.next()取出下一条到时的消息,然后执行msg.target.dispatchMessage(msg),最终回调到Handler的handleMessage或Runnable
延时消息与阻塞唤醒
MessageQueue中会按照when字段升序排列,next取消息时如果队头还没到时间,就计算等待时间,调用nativePollOnce进入epoll等待,释放CPU,当新消息插入对头或时间更早时,通过nativeWake()唤醒等待,所以主线程的Looper.loop()不会导致CPU空转,无消息时线程会挂起
主线程与子线程:
主线程在应用启动时已调用prepareMainLooper和loop,所有可以直接创建Handler更新ui
子线程必须手动调用Looper.prepare()和loop(),或者使用HandlerThread
内存泄漏与优化
调用handler.removeCallbacksAndMessages()清空所有待处理消息,现在更推荐用Lifecycle组件配合LiveData
高级特性
同步屏障:通过postSyncBarrier插入屏障消息,优先处理异步消息,如view的绘制调度
IdleHandler:在MessageQueue空闲时回调,可做低优先级任务,如GC触发
HandlerThread:自带Looper的子线程,需注意及时quit释放
Binder机制 进程间的通信
选用binder的理由:
1、安全性:UID/PID可信传递,内核可以识别调用方身份,便于权限校验,而Socket无法确认对方真实身份。
2、高效性:一次数据拷贝(通过copy_from_user到内核空间,再映射到目标进程,本质是拷贝一次),比管道,Socket两次拷贝快,而共享内存缺乏同步机制且安全控制弱
3、面向对象:基于C++接口,服务端暴露IInterface,客户端像调用本地方法一样调用远程服务,开发体验好
4、引用计数与死亡通知:自动管理服务生命周期,死亡时能通知客户端,避免悬空指针
核心原理:
基于Client-Server-驱动三层架构
注册服务:ServiceManager再binder驱动中注册为句柄0,系统服务如AMS,WMS启动时,通过addService将服务名和Binder引用注册到ServiceManager。
获取服务:客户端通过getService来查询服务,得到服务Binder的句柄,封装成远程代理Proxy,客户端拿到的是本地代理对象
调用服务:客户端调用Proxy的方法时,将参数打包到Parcel,通过transact将数据发给Binder驱动。驱动找到对应的服务端Binder实体,唤醒服务端线程处理。服务端收到后解析参数,执行真正方法,将结果写回Parcel,返回给客户端,是同步的,客户端线程会被挂起等待返回,
数据传递:大件数据利用ashmem匿名共享内存传递,Bitmap的writeToParcel内部用了Blob和FileDescriptor来传递共享内存fd,因此能够零拷贝传递大图。
Binder线程池与同步:
每个进程再初始化Binder时会启动一个Binder线程池,默认最大16个线程,服务端需要保证线程安全
隐式意图
让我们在不明确指定类名的情况下,通过描述要做什么来启动其他应用的activity。
1、隐式意图的匹配机制
依靠action,category,data三要素与IntentFilter进行匹配
2、实战场景
打开网页,分享内容,调用系统拍照,自定义协议拉起
3、安全陷阱和防护
4、包可见性限制
