1.相关问题
- Activity的显示原理(window/DecorView/Viewroot)
- Activity的UI刷新机制(Vsync/Choreographer)
- UI绘制原理(Messure/Layout/Draw)
- Surface原理(Surface/SurfaceFlinger)
2.Activity的显示原理
我们从setContentView入手,Activity里面的Window实质是PhoneWindow,这里的是PhoneWindow的里面的
increase() # setContentView
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
// 1 构建DecorView
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
// 3加载布局文件到DecorView
mLayoutInflater.inflate(layoutResID, mContentParent);
}
private void installDecor() {
//new DecorView
mDecor = new DecorView(context, featureId, this, getAttributes());
mDecor.addView();
// 2
mContentParent = findViewById(R.id.content)
}
小结:
- 1.创建DecorView
- 2.inflate我们的布局文件
- 将我们的布局文件添加到DecorView里面去。
注意 setContentView之后 页面并没有展示,它仅仅是构建了一下数据结构而已吗,接着看,这里 oncreate就走完了。接着看;
resume
final void handleResumeActivity(IBinder token) {
// onResume 回调
r = performResumeActivity(token, clearHide, reason);
if (r.window == null && !a.mFinished && willBeVisible) {
//拿到PhoneWindow
r.window = r.activity.getWindow();
//拿到Decorview
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
//拿到WindowManager
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
//添加view
wm.addView(decor, l);
}
}
接着我们看看WindowManager是怎么添加View的
public interface WindowManager extends ViewManager {}
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
private final Context mContext;
private final Window mParentWindow;
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
}
可知,WindowManager是一个接口,其实现类是在WindowManagerImpl,WindowManagerImpl里面的使用了桥接器的模式,将操作window的任务交接给了WindowManagerGlobal。
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
ViewRootImpl root;
View panelParentView = null;
//1创建ViewRootImpl
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
//2 将View添加到View root里面去
mViews.add(view);
//3
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
//4 调用ViewRootImpl的setView
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
// Schedule the first layout -before- adding tothe window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
//调用刷新机制 这个是View绘制的开始
requestLayout();
//IPC 调用 到WMS里面去
res = mWindowSession.addToDisplay(mWindow);
}
}
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
//注意这里的checkThread
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
这里高度注意,==checkThread里面的作用,为啥不能在子线程里面刷新ui,这里是原因所在,==
==mChoreographer== 这个是干什么的,在卡顿布局优化里面有用到。 Choreographer是用获取FPS的,可以带到线上去,具备实时性,在API16后可以使用
private void performTraversals() {
//向WMS申请surface
Surface surface = new Surface();
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
performLayout(lp, mWidth, mHeight);
performDraw();
}
这里要注意,==在绘制之前首先向WMS申请surface==,这一步非常重要,因为后面的所以绘制和显示都是在surface上进行的。
绘制结束后,会通过Session 这个Binder对象调用到WMS的addWindow里面去,对WMS而言,它管理这Window的显示层级。
==ViewRootImpl是DecorView和WMS通信的桥梁,里面的重点是session==
WMS的作用:
- 分配Surface
- 掌管surface显示顺序以及位置尺寸
- 控制窗口动画
- 输入事件分发
3.问题:Activity的显示原理
- 1.PhoneWindow是什么,怎么创建
- 2.setContentView的原理,DecorView是什么
- 3.ViewRoot是什么,有什么作用
- 4.View的显示原理是什么,WMS发挥的作用