答题要点
-
什么是UI线程?
-
UI线程也就是刷新UI所在的线程
-
UI是单线程刷新的(如果是多线程导出上锁容易导致问题)
-
UI线程的启动流程,消息循环是怎么创建的
-
了解Android的UI显示原理,UI线程和U|体系之间是怎么关联的?
Activity.runOnUiThread(Runnable)与view.post(Runnable)
-
Activity.runOnUiThread(Runnable)
-
结论1:对于Activity来说,UI线程就是主线程
-
图34
-
view.post(Runnable)
-
结论2:对View来说,它的U线程就是ViewRootlmpl创建的时候所在的线程!
-
图35
-
子线程刷新UI的问题
-
结论:只有创建了view树的线程,才能访问它的子view
-
如图36
-
结论3:Activity的DecorVie对应的ViewRootlmpl是在主线程创建的
-
如图37
关于UI线程的三个结论
-
对Activity来说,UI线程就是主线程
-
activity.runOnUiThread()
-
对View来说,UI线程就是ViewRootlmpl创建的时候所在的线程
-
View.post(Runnable r)
-
Activity的DecorView对应的ViewRootlmpl是在主线程创建的
-
checkThread
子线程刷新UI可以么?
可以,代码如下
new Thread(){
@Override
public void run(){
//因为添加window是IPC操作,回调回来时,需要handler切换线程,所以需要Looper
Looper.prepare();
…
getWindowManager().addView(view,params);
//开启looper,循环取消息。
Looper.loop()
}
}.start();
Looper.prepare()与Looper.prepareMainLooper()的区别
-
Looper.prepareMainLooper(),应用进程启动之后MainLooper就已经设置好了
-
prepare(false)表示looper不能退出,对于mainLooper来说looper是不能退出的,其他线程是可以退出的,调用主线程的looper.quit是会抛出异常的
总结
-
UI线程指的是刷新UI的线程,由于ViewRootImpl是在主线程中创建的,所以实际上指的就是主线程
-
UI线程的启动实际上就是主线程的启动,分三步
-
①Zygote fork进程
-
②启动binder线程
-
③ 执行入口函数 ActivityThread.main()
-
消息循环时通过主线程的Looper开启的
1. 说说Service的启动原理
考察点
-
service启动有哪几种方式?
-
startService
-
bindService
-
区别:bindServcie不会触发onStartCommand
-
service启动过程中主要流程有哪些?
-
service启动过程涉及哪些参与者,通信过程是怎样的?
代码分析
主要的启动流程
-
如果Service启动了,直接调用onStartCommand
-
如果Service没有启动
-
进程启动了
-
启动Service
-
调用onStartCommand
-
进程没有启动
-
启动进程
-
启动Service
-
调用onStartCommand
启动过程涉及哪些参与者,以及通信过程
-
进程A要开启一个Service,向AMS发起了startService调用
-
如果AMS发现Service进程没有启动,就会通过socket向zygote进程发起启动进程的请求
-
zygote进程会启动应用进程
-
应用进程启动之后,就会执行ActivityThread main函数
-
在入口函数中向AMS发起attchApplication的binder调用,AMS就知道了应用进程已经就绪了
-
然后AMS会向应用发起bindApplication的binder调用,让应用创建自己的Application
-
接下来就开始处理这个应用进程里pending的一些应用组件,比如Service相关,这里连发了两条请求,这两个请求都是在主线程中执行的
-
scheduleCreateServices用于在应用端create Service
-
cheduleServiceArgs用于在应用端调用onStartCommand
-
如图41
总结
-
首先回答出启动方式,答案如上
-
然后回答出启动过程中的主要流程
-
最后回答出service启动过程涉及哪些参与者,通信过程是怎样的?
2.说说Service的绑定原理
考察点:
-
bindService用法
-
了解bindServcie的大致流程
-
bindService涉及哪些参与者,通信过程是怎样的?
用法: 图43
总体流程
-
首先应用向AMS发起bindService调用
-
AMS检查是否有binder句柄
-
如果有,就会将binder句柄回调给应用
-
如果没有,AMS就会向Service请求句柄,Service会将句柄发布到AMS,然后AMS会将binder句柄回调给应用
-
应用在拿到binder句柄之后,就可以向Service发起binder调用了
-
应用端bindService的时候会带一个IserviceConnection对象
-
这个对象是一个Bindder对象,把这个对象传到AMS之后,AMS就会将它保存起来
-
等到Service绑定成功了,AMS就会调用IserviceConnection的connected函数来主动通知应用端
-
然后IServiceConnection持有了ServiceConnection的引用,这意味着可以调用ServiceConnection的函数
-
值得注意的是,IServiceConnection和ServiceConnection不一定是一对一的关系
-
一个context和一个ServiceConnection构成一个二元组,这个二元组跟IserviceConnection是一对一的关系
-
这意味着同一个ServiceConnection用不同的Context去bind这个Service的时候,就会对应不同的IserviceConnection
-
同样,同一个Context用不同的ServiceConnection去bind这个Service的话,那么也会对应不同的IServiceConnection
-
对于AMS来说,他只认IServiceConnection,只要IServiceConnection不同,他就认为这是不同的Connection
bindService实现原理 bindService从应用端发到了AMS, 在AMS中处理函数就是bindServiceLocked
首先来看一组数据结构
-
应用端一个Service在AMS中对应一个ServiceRecord
-
一个ServiceRecord又可以包含一个或多个IntentBindRecord
-
一个IntentBindRecord又可以包含一个或多个AppBindRecord
-
一个AppBindRecord又可以包含一个或多个ConnectionRecord
下面看具体流程
-
启动Service会最终调用到AMS中的bringUpServiceLocked函数,之后的流程如下图
-
图46
onRebind什么时候调用
- 图47
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
最后
如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。
最后文末放上一个福利:GitHub地址
PS:我GitHub中有大量高阶Android学习视频资料和面试资料包~
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-MX8OLtuH-1710677255651)]
最后
如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。
[外链图片转存中…(img-ERWGg7oH-1710677255652)]
最后文末放上一个福利:GitHub地址
PS:我GitHub中有大量高阶Android学习视频资料和面试资料包~
欢迎大家一起交流讨论啊~