-
如何实现多线程的同步
- volitile主要是在CPU指令禁止重排和多线程访问变量时变量发生变化时,各线程的值是同时变化的。
只有一个线程写,其他都是读,用 volatile - 多个线程写,用 Synchronized
- 多个线程写+设置超时+自行决定释放,用 ReentranLock
- 想提高效率,不单单一个线程进入临界区,用并发包,如:ConcurrentHashMap、LinkBlockingQueue、AtomicXXX。
- 读比写多,用 CopyOnWriteXXX
- 希望控制线程的并发数量,用 Semaphore 信号量
- 想让指定线程等待其他线程,用 CountDownLatch
- volitile主要是在CPU指令禁止重排和多线程访问变量时变量发生变化时,各线程的值是同时变化的。
-
Android 进程间的通信方式
20211215195246.jpg
https://zhuanlan.zhihu.com/p/149870923
-
说说Activity加载的流程?
-
App 启动流程(基于Android8.0):
- 点击桌面 App 图标,Launcher 进程采用 Binder IPC(具体为ActivityManager.getService 获取 AMS 实例) 向 system_server 的 AMS 发起 startActivity 请求
- system_server 进程收到请求后,向 Zygote 进程发送创建进程的请求;
- Zygote 进程 fork 出新的子进程,即 App 进程
- App 进程创建即初始化 ActivityThread,然后通过 Binder IPC 向 system_server 进程的 AMS 发起 attachApplication 请求
- system_server 进程的 AMS 在收到 attachApplication 请求后,做一系列操作后,通知 ApplicationThread bindApplication,然后发送 H.BIND_APPLICATION 消息
- 主线程收到 H.BIND_APPLICATION 消息,调用 handleBindApplication 处理后做一系列的初始化操作,初始化 Application 等
- system_server 进程的 AMS 在 bindApplication 后,会调用 ActivityStackSupervisor.attachApplicationLocked,之后经过一系列操作,在 realStartActivityLocked 方法通过 Binder IPC 向 App 进程发送 scheduleLaunchActivity 请求;
- App进程的 binder 线程(ApplicationThread)在收到请求后,通过 handler 向主线程发送 LAUNCH_ACTIVITY 消息;
- 主线程收到 message 后经过 handleLaunchActivity,performLaunchActivity 方法,然后通过反射机制创建目标 Activity;
- 通过 Activity attach 方法创建 window 并且和 Activity 关联,然后设置 WindowManager 用来管理 window,然后通知 Activity 已创建,即调用 onCreate
- 然后调用 handleResumeActivity,Activity 可见
-
附图:
app-launch.png
-
补充:
- ActivityManagerService 是一个注册到 SystemServer 进程并实现了 IActivityManager 的 Binder,可以通过 ActivityManager 的 getService 方法获取 AMS 的代理对象,进而调用 AMS 方法
- ApplicationThread 是 ActivityThread 的内部类,是一个实现了 IApplicationThread 的 Binder。AMS通过 Binder IPC 经 ApplicationThread 对应用进行控制
- 普通的 Activity 启动和本流程差不多,至少不需要再创建 App 进程了
- Activity A 启动 Activity B,A 先 pause 然后 B 才能 resume,因此在 onPause 中不能做耗时操作,不然会影响下一个 Activity 的启动
-
Android View 深度分析requestLayout、invalidate与postInvalidate
https://blog.csdn.net/a553181867/article/details/51583060
另外,我解释一下文章里没有说明,但是很关键的一个地方:为什么方法层层向上调用时,最终会传递到ViewRootImpl中。我们知道View树的根节点是DecorView,DecorView通过WindowManagerGlobal的addView方法添加到Window中,下面是addView方法的源码:
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
...
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
...
root.setView(view, wparams, panelParentView);
...
}
可以看到,addView方法只做了一些准备工作,最终又调用了ViewRootImpl的setView方法完成添加,看下setView方法的源码:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
requestLayout();
...
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
...
view.assignParent(this);
}
setView方法,通过requestLayout方法绘制出View树,通过mWindowSession.addToDisplay方法向WMS注册自己,使自己可以显示到屏幕上。貌似工作都已经完成了,但是最后又调用了View的assignParent方法,看下它的源码:
void assignParent(ViewParent parent) {
if (mParent == null) {
mParent = parent;
} else if (parent == null) {
mParent = null;
} else {
throw new RuntimeException("view " + this + " being added, but"
+ " it already has a parent");
}
}
这就非常明确了,DecorView调用这个方法,把ViewRootImpl设为自己的父View。所以方法调用沿着View树往上传递时,最终会传递到ViewRootImpl中。