前言:
Android系统中的窗口是屏幕上的一块用于绘制各种UI元素并可以响应用户输入的一个矩形区域, 从原理上来讲, 窗口的概念是独自占有一个Surface实例的显示区域, 例如Dialog、Activity的界面、壁纸、状态栏以及Toast等都是窗口;
Surface是一块画布, 应用可以随心所欲地通过Canvas或者OpenGL在其上作画, 然后通过SurfaceFlinger将多块Surface的内容按照特定的顺序进行混合并输出到FrameBuffer, 从而将Android界面显示给用户;
既然每个窗口都有一块Surface供自己涂鸦, 必然需要一个角色对所有窗口的Surface进行协调管理. 于是WMS应运而生, WMS为所有窗口分配Surface, 掌管Surface的显示顺序以及位置尺寸, 控制窗口动画, 并且还是输入系统的重要的中转站;
一、WindowManagerService实例的创建
- WindowManagerService运行在system_server进程中, system_server进程在创建时会初始化WindowManagerService的实例;
- 窗口管理服务, 复杂窗口的启动, 添加, 删除等;
- 这篇笔记希望分析一下Activity的展示与AMS到底有怎样的关系?
1.1 SystemServer.main
system_server进程被创建以后, 会调用SystemServer.main方法
public final class SystemServer {
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
//**
* 核心是这三个方法, AMS在第一个方法中被初始化;
*/
startBootstrapServices();
startCoreServices();
startOtherServices();
}
private void startBootstrapServices() {
//**
* 通过SSM拿到AMS的实例;
*/
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
}
}
二、Activity端
Activity启动的流程比较复杂, 目前结合Activity的生命周期只列出Activity启动时的方法调用链
ActivityMain.main--->
ActivityThread.handleLaunchActivity--->
ActivityThread.performLaunchActivity--->
ActivityThread.handleResumeActivity--->
ActivityThread.performResumeActivity--->
2.1 ActivityThread.handleLaunchActivity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
// 获取AMS的实例;
WindowManagerGlobal.initialize();
Activity a = performLaunchActivity(r, customIntent);
}
2.2 WindowManagerGlobal.initialize
public static void initialize() {
getWindowManagerService();
}
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
// 进程间通信获取WindowManagerService实例;
sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
}
// WindowManagerGlobal持有sWindowManagerService的引用;
return sWindowManagerService;
}
}
2.3 ActivityThread.performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// 通过Activity.attach将Activity, Window, WindowManager, WMS进行绑定;
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
}
2.4 Activity.attach
先理一下各个变量之间的继承关系:
public class Activity {
Window mWindow = new PhoneWindow();
WindowManager mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(PhoneWindow);
}
public class WindowManagerImpl extends WindowManager {
private final Window mParentWindow = new PhoneWindow();
}
public class Activity {
final void attach(...) {
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
...
mWindowManager = mWindow.getWindowManager();
}
}
三、ActivityThread.handleResumeActivity
在handleLauncherActivity里面会执行onCreate方法, 然后触发对布局的解析, 根节点为DecorView, resume方法里面对View树进行遍历测量, 布局, 绘制;
3.1 ActivityThread.handleResumeActivity
final void handleResumeActivity(...) {
// 其他几个地方看到了再进行分析吧, 目前先分析这个方法;
r.activity.makeVisible();
}
3.2 Activity.makeVisible
void makeVisible() {
if (!mWindowAdded) {
// 由前面的关系可知, 这里的wm指向的是ViewManagerImpl;
// ViewManagerImpl与DecorView之间有什么关系?
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
3.3 WindowManagerImpl.addView
// mGlobal持有WMS;
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
// 1. mParentWindow指向的是PhoneWindow;
// 2. view指向的是DecorView;
// 3. setContentView时, 已经将PhoneWindow与DecorView进行了关联;
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
3.4 WindowManagerGlobal.addView
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
int index = findViewLocked(view, false);
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
// WindowManagerGlobal持有两个容器: mViews用于存储DecorView, mRoots用于存储ViewRootImpl;
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// 这里以及后续的View都默认为DecorView, ViewRootImpl通过setView将DecorView与自己进行绑定;
root.setView(view, wparams, panelParentView);
}
}
3.5 ViewRootImpl.setView
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
// 现在只看这三行代码:
// 1. 将DecorView赋值给View mView;
// 2. 重新布局时会调用这个requestLayout, 如果在子线程中操作UI会报错, 报错原因就在这个requestLayout中;
// 3. 将ViewRootImpl赋值给DecorView, 将两者进行相互绑定, DecorView为每一个视图的根节点, 其内部维护ViewRootImpl
// 实例从而实现了每次View通过ViewRootImpl的渲染;
mView = view;
requestLayout();
view.assignParent(this);
}
@Override
public void requestLayout() {
// 通常所说的不能在非UI线程中操作UI就是在这里进行判断的;
checkThread();
mLayoutRequested = true;
// 这个方法会触发View的测量, 绘制, 布局操作;
scheduleTraversals();
}
void checkThread() {
// 在初始化ViewRootImpl时会在当前线程生成一个常量mThread, 操作View时判断当前线程是否与ViewRootImpl
// 初始化时的线程是同一个线程, 如果不是就会报错;
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
final Thread mThread;
public ViewRootImpl(Context context, Display display) {
mThread = Thread.currentThread();
}
网友评论