我懵了,面试大厂被熟悉的 App 启动流程和 RecycleView 连环三问坑了
里面涉及到哪些重要的成员呢?都分别负责了什么,比如 AMS?
启动流程了解后,对我们开发有什么帮助呢?
说一下 APP 的启动流程
Launcher
被调用点击事件
,转到 Instrumentation 类的 startActivity 方法。
Instrumentation
通过跨进程通信告诉 AMS 要启动应用的需求。AMS
反馈 Launcher,让 Launcher 进入 Paused 状态Launcher
进入 Paused 状态,AMS 转到 ZygoteProcess 类,并通过 socket 与 Zygote 通信,告知 Zygote 需要新建进程。Zygote
?fork 进程,并调用 ActivityThread 的 main 方法,也就是 app 的入口。ActivityThread
的 main 方法新建了 ActivityThread 实例,并新建了 Looper 实例,开始 loop 循环。同时
ActivityThread
也告知 AMS,进程创建完毕,开始创建 Application,Provider,并调用 Applicaiton 的 attach,onCreate 方法。最后就是创建上下文,通过类加载器加载 Activity,调用 Activity 的
onCreate
方法。
里面涉及到哪些重要的成员呢?都分别负责了什么,比如 AMS?
init进程
,Android 系统启动后,Zygote 并不是第一个进程,而是 linux 的根进程 init 进程,然后 init 进程才会启动 Zygote 进程。Zygote进程
,所有 android 进程的父进程,当然也包括 SystemServer 进程SystemServer进程
,正如名字一样,系统服务进程,负责系统中大大小小的事物,为此也是启动了三员大将(ActivityManagerService,PackageManagerService,WindowManagerService)以及 binder 线程池。ActivityManagerService
,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,对于一些进程的启动,都会通过 Binder 通信机制传递给 AMS,再处理给 Zygote。PackageManagerService
,主要负责应用包的一些操作,比如安装,卸载,解析 AndroidManifest.xml,扫描文件信息等等。WindowManagerService
,主要负责窗口相关的一些服务,比如窗口的启动,添加,删除等。Launcher
,桌面应用,也是属于应用,也有自己的 Activity,一开机就会默认启动,通过设置 Intent.CATEGORY_HOME 的 Category 隐式启动。
启动流程了解后,对我们开发有什么帮助呢?
分析源码的目的一直都不是为了学知识而学,而是理解了这些基础,我们才能更好的解决问题。学习了 App 的启动流程,我们可以再思考下一些之前没理解透的问题。
1)比如启动优化
,分析启动过程,其实可以优化启动速度的地方有三个地方:
Application的attach方法
,MultiDexApplication 会在方法里面会去执行 MultiDex 逻辑。所以这里可以进行 MultiDex 优化,比如今日头条方案就是单独启动一个进程的 activity 去加载 MultiDex。Application的onCreate方法
,大量三方库的初始化都在这里进行,所以我们可以开启线程池,懒加载等等。把每个启动任务进行区分,哪些可以子线程运行,哪些有先后顺序。Activity的onCreate方法
,同样进行线程处理,懒加载。或者预创建 Activity,提前类加载等等。
2)又比如插件化,通过了解启动流程可以知道哪些地方可以用来hook
,从而完成我们侵入代码,替换 Activity 的工作。
3)还有上次说过的 Activity 显示 View 的过程,我们才知道什么时候进行DecorView
的加载,什么时候进行 view 绘制等等
RecycleView 三问—腾讯真题
Recycleview 相比也是每个 Android 开发者熟得不能再熟的控件了,但是你对他又真的了解多少呢?看看今天的三问你都能答得上来吗?
和 listview 区别
Recycleview 有几级缓存,缓存过程?
说说 RecyclerView 性能优化。
和 listview 区别
Recycleview布局效果更多
,增加了纵向,表格,瀑布流等效果Recycleview去掉了一些api
,比如 setEmptyview,onItemClickListener 等等,给到用户更多的自定义可能Recycleview去掉了设置头部底部item的功能
,专向通过 viewholder 的不同 type 实现Recycleview实现了一些局部刷新
,比如 notifyitemchangedRecycleview自带了一些布局变化的动画效果
,也可以通过自定义 ItemAnimator 类实现自定义动画效果Recycleview缓存机制更全面
,增加两级缓存,还支持自定义缓存逻辑
Recycleview 有几级缓存,缓存过程?
Recycleview 有四级缓存,分别是mAttachedScrap(屏幕内),mCacheViews(屏幕外),mViewCacheExtension(自定义缓存),mRecyclerPool(缓存池)
mAttachedScrap(屏幕内)
,用于屏幕内 itemview 快速重用,不需要重新 createView 和 bindViewmCacheViews(屏幕外)
,保存最近移出屏幕的 ViewHolder,包含数据和 position 信息,复用时必须是相同位置的 ViewHolder 才能复用,应用场景在那些需要来回滑动的列表中,当往回滑动时,能直接复用 ViewHolder 数据,不需要重新 bindView。mViewCacheExtension(自定义缓存)
,不直接使用,需要用户自定义实现,默认不实现。mRecyclerPool(缓存池)
,当 cacheView 满了后或者 adapter 被更换,将 cacheView 中移出的 ViewHolder 放到 Pool 中,放之前会把 ViewHolder 数据清除掉,所以复用时需要重新 bindView。
四级缓存按照顺序需要依次读取。所以完整缓存流程是:
保存缓存流程:
插入或是删除
itemView
时,先把屏幕内的 ViewHolder 保存至AttachedScrap
中滑动屏幕的时候,先消失的 itemview 会保存到
CacheView
,CacheView 大小默认是 2,超过数量的话按照先入先出原则,移出头部的 itemview 保存到RecyclerPool缓存池
(如果有自定义缓存就会保存到自定义缓存里),RecyclerPool 缓存池会按照 itemview 的itemtype
进行保存,每个 itemTyep 缓存个数为 5 个,超过就会被回收。
获取缓存流程:
AttachedScrap 中获取,通过 pos 匹配 holder——>获取失败,从
CacheView
中获取,也是通过 pos 获取 holder 缓存 ——>获取失败,从自定义缓存
中获取缓存——>获取失败,从mRecyclerPool
中获取 ——>获取失败,重新创建viewholder
——createViewHolder 并 bindview。
需要注意的是,如果从缓存池找到缓存,还需要重新 bindview。
说说 RecyclerView 性能优化。
bindViewHolder
方法是在 UI 线程进行的,此方法不能耗时操作,不然将会影响滑动流畅性。比如进行日期的格式化。对于新增或删除的时候,可以使用
diffutil
进行局部刷新,少用全局刷新对于
itemVIew
进行布局优化,比如少嵌套等。25.1.0 (>=21)及以上使用
Prefetch
?功能,也就是预取功能,嵌套时且使用的是 LinearLayoutManager,子 RecyclerView 可通过 setInitialPrefatchItemCount 设置预取个数加大
RecyclerView缓存
,比如 cacheview 大小默认为 2,可以设置大点,用空间来换取时间,提高流畅度如果高度固定,可以设置
setHasFixedSize(true)
来避免 requestLayout 浪费资源,否则每次更新数据都会重新测量高度。
void onItemsInsertedOrRemoved() {
if (hasFixedSize) layoutChildren();
else requestLayout();
}
如果多个
RecycledView
?的 Adapter 是一样的,比如嵌套的 RecyclerView 中存在一样的 Adapter,可以通过设置?RecyclerView.setRecycledViewPool(pool);
来共用一个?RecycledViewPool
。这样就减少了创建 VIewholder 的开销。在 RecyclerView 的元素比较高,一屏只能显示一个元素的时候,第一次滑动到第二个元素会卡顿。这种情况就可以通过设置额外的缓存空间,重写
getExtraLayoutSpace
方法即可。
new LinearLayoutManager(this) {
@Override
protected int getExtraLayoutSpace(RecyclerView.State state) {
return size;
}
};
设置
RecyclerView.addOnScrollListener();
来在滑动过程中停止加载的操作。减少对象的创建,比如设置监听事件,可以全局创建一个,所有 view 公用一个 listener,并且放到
CreateView
里面去创建监听,因为 CreateView 调用要少于 bindview。这样就减少了对象创建所造成的消耗
评论