两个情况,一个是DecorView,也就是activity的创建,另一种就是直接window添加view,如dialog等
Activity的启动中会有:
1。performLaunchActivity()主要做了以下几件事:
创建Activity。
创建Context。
调用Activity.attach(),创建Window,关联WindowManager。
调用Activity.onCreate()。
调用Activity.onStart()。
2.handleResumeActivity()处理的事情比较多。我总结为以下几个过程:
通过performResumeActivity()处理Activity的onRestart onResume的生命周期。
将DecorView设置为InVisible。
通过WindowManager.addView()将DecorView绘制完成。
将DecorView设置为Visiable。
通知AMS Activity启动完成。
WindowManager直接添加view的例子:
//1. 控件
Button button = new Button(this);
button.setText("Window Button");
//2. 布局参数
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSPARENT);
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
layoutParams.x = 100;
layoutParams.y = 300;
// 必须要有type不然会异常: the specified window type 0 is not valid
layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
//3. 获取WindowManager并添加控件到Window中
WindowManager windowManager = getWindowManager();
windowManager.addView(button, layoutParams);
WindowManagerGlobal
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
//新建ViewRootImpl
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
//调用ViewRootImpl的setview
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
ViewRootImpl
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
。。。
requestLayout();
。。
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
//windowsession
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
} catch (RemoteException e) {}
}
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//1. 实际是View绘制的入口(测量、布局、重绘)--内部通过mChoreographer去监听下一帧的刷新信号
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
//Session.java
@Override
public int addToDisplay(IWindow window, ...) {
return mService.addWindow(this, window, ...);
}
//WindowManagerService.java
public int addWindow(Session session, IWindow client, ...) {
/**=================================
* 1. 检查工作
* 1-权限检查和设置相关
* 2-检查是否重复添加---Binder对象会存储在HashMap<IBinder, WindowState>中
*=================================*/
...
if (mWindowMap.containsKey(client.asBinder())) {
...
}
// 2. 返回WmS中存在的对应父窗口,若不存在则返回null
WindowState attachedWindow = windowForClientLocked(null, attrs.token, false);
...
/**===========================================
* 3. 从WmS中寻找对应的WindowToken, 并且处理合法性
* 1-例如:对于子窗口来说,WmS中必须有对应的Token才能添加
* 2-例如:token不为null且是应用窗口是必须要有个windowToken
*============================================*/
WindowToken token = mTokenMap.get(attrs.token);
/**
* ...检查Token合法性...
*/
// 4. 创建窗口
WindowState win = new WindowState(session, client, token, attachedWindow, attrs, viewVisibility);
/**==============================================
* 5. 额外的操作、信息保存等
* 1. 如果是Toast,则此窗口不能够接收input事件
* 2. Token添加到WmS中
* 3. 窗口信息添加到WmS中
* 4. 将窗口(WindowState)添加到Session中
* 5. 对于应用启动时显示的窗口,设置token
*==============================================*/
// 1、如果是Toast,则此窗口不能够接收input事件
mPolicy.adjustWindowParamsLw(win.mAttrs);
// 2、从上述代码中得出是否要添加Token,若是则添加Token添加到WmS中
if (addToken) {
mTokenMap.put(attrs.token, token);
mTokenList.add(token);
}
// 3、窗口信息添加到WmS中
mWindowMap.put(client.asBinder(), win);
// 4、将窗口添加到Session中
win.attach();
// 5、对于应用启动时显示的窗口,设置token
token.appWindowToken.startingWindow = win;
...
}
接着会通过WindowSession最终来完成Window的添加过程。在下面的代码中mWindowSession类型是IWindowSession,它是一个Binder对象,真正的实现类是Session,也就是说这其实是一次IPC过程,远程调用了Session中的addToDisPlay方法。
refer:https://blog.csdn.net/cpcpcp123/article/details/115266556
refer: https://blog.csdn.net/feather_wch/article/details/81437056
网友评论