一、wms体系
-
1.Window:android视图架构中,window就是一个窗口概念,android中所有的视图都是依赖窗口显示的
-
2.WindowManager:管理类负责对window的管理:新增、更新、移除
-
3.WMS:窗口的系统管理者,负责窗口的启动、添加、移除,也负责管理窗口的大小和层级(window的显示层级)
窗口包括什么?
窗口分类及优先级?
窗口整体架构
添加一个window的流程
流程一:创建window######
//onstart生命周期 onresume有关 和executeLifecycleState相关
private Activity performLaunchActivity(ActivityClientRecord r,
Intent customIntent) {
// 执行 Activity 的 attach、初始化 Window 等
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,
r.assistToken);
@UnsupportedAppUsage
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
//创建phonewindow
mWindow = new PhoneWindow(this, window, activityConfigCallback);
//----设置window相关属性
//与windowsManagerService进行关联
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
流程二:创建DecorView
//phonewindow的方法中
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//安装Decor
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
private void installDecor()
if (mDecor == null) {
//创建decorview
mDecor = generateDecor(-1);
protected DecorView generateDecor(int featureId) {
Context context;
//return new DecorView
return new DecorView(context, featureId, this,getAttributes());
}
流程三:addView
//ActivityThread.java
@Override
public void handleResumeActivity(IBinder token,
boolean finalStateRequest, boolean isForward,String reason) {
//调用addview方法
wm.addView(decor, l);
//WindowManagerImpl.java
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
//实际调用到了WindowManagerGlobal.java实现
mGlobal.addView(view, params,
mContext.getDisplayNoVerify(), mParentWindow,mContext.getUserId());
}
//WindowManagerGlobal.java
//全局的管理者。 是WindowManagerImpl的真正实现
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
ViewRootImpl root;
//创建ViewRootimpl对象
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
root.setView(view, wparams, panelParentView, userId);
//ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs,
View panelParentView, int userId) {
//一系列的检查判断
//调用addToDisplay
mWindowSession.addToDisplayAsUser
}
//会调用到WMS的addWindow方法
public int addWindow
WindowManagerGlobal管理DecorView,创建ViewRootImpl实例,来进行对view的渲染工作。
ViewRootImpl用来做什么?
- 1.管理View树
- 2.出发view的测量、布局、绘制
- 3.输入事件响应的接受
- 4.负责与wms进行进程间通信
ViewRootImpl接收到同步信号会出发view树的绘制。
与wms进行通信
更新window的流程
//看下代码 WindowManagerImpl会调用到Global中的updateViewLayout
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
//调用到WindowManagerGlobal.java
mGlobal.updateViewLayout(view, params);
}
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
//窗口参数
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
//view设置参数
view.setLayoutParams(wparams);
synchronized (mLock) {
int index = findViewLocked(view, true);
ViewRootImpl root = mRoots.get(index);
//更新参数
mParams.remove(index);
mParams.add(index, wparams);
//调用到ViewRootImpl方法
root.setLayoutParams(wparams, false);
}
}
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
//触发绘制
scheduleTraversals();
}
@UnsupportedAppUsage
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier =
//发送同步消息
mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
2.UI刷新
摘自百度: 电影放映的标准是每秒放映24帧,每秒遮挡24次,刷新率是每秒48次。这里的帧就是画面,也就是说电影每秒放映24幅画面,以达到动画的效果。
研究表明,人眼承受的极限为每秒55帧,还有研究表明,每秒60帧以上可以明显提升观众的观影感受。每秒120帧是每秒24帧的5倍,采用这样的拍摄技术可以让画面更加栩栩如生,让观众仿佛置身其中,给人一种似真似幻的感觉。
在手机上,帧数真是达到120hz。通常以60帧为主流。1秒60幅画面的切换。1000/60平均约16ms就会更新一幅画面。
当我们代码调用settext去设置一个值,就会触发ui的刷新。看一下刷新的流程。
跟踪下代码
/最终调用到setText方法中
@UnsupportedAppUsage
private void setText(CharSequence text, BufferType type,
boolean notifyBefore, int oldlen) {
if (mLayout != null) {
//进行布局检测
//检查全新的文本是否需要新的视图布局或者仅仅是一个新的文本布局。
checkForRelayout();
}
}
private void checkForRelayout() {
//判断是否是更改textview的布局还是只是设置值
//然后调用invalidate()方法
invalidate();
}
//调用到父类view的invalide方法中
public void invalidate(Rect dirty) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
//实际调用
invalidateInternal(dirty.left - scrollX, dirty.top - scrollY,
dirty.right - scrollX, dirty.bottom - scrollY, true, false);
}
//继续调用到viewgroup的invalidateChild
//这是一个过渡方法会调用到
public final void invalidateChild(View child, final Rect dirty) {
if (mParent != null) {
//调用到ViewRootImpl的方法中
mParent.onDescendantInvalidated(this, target);
}
}
//ViewRootImpl.onDescendantInvalidated 调用到invalidate
@UnsupportedAppUsage
void invalidate() {
mDirty.set(0, 0, mWidth, mHeight);
if (!mWillDrawSoon) {
//触发绘制
scheduleTraversals();
}
}
@UnsupportedAppUsage
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//发送同步屏障消息
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//执行代码
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
//调用代码Choreographer.postCallbackDelayedInternal
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
if (dueTime <= now) {
//等待执行命令
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
//等待同步垂直信号vsync
if (USE_VSYNC) {
//省略
}
}
//接收到vsync信号后,会执行到
rivate final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
long now = System.nanoTime();
if (timestampNanos > now) {
Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
+ " ms in the future! Check that graphics HAL is generating vsync "
+ "timestamps using the correct timebase.");
timestampNanos = now;
}
if (mHavePendingVsync) {
Log.w(TAG, "Already have a pending vsync event. There should only be "
+ "one at a time.");
} else {
mHavePendingVsync = true;
}
mTimestampNanos = timestampNanos;
mFrame = frame;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
//执行run方法 doFrame
doFrame(mTimestampNanos, mFrame);
}
}
//doFrame会封装一系列的消息,然后执行
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
//执行到CallbackRecord.run方法
//又调用回ViewRootImpl.TraversalRunnable方法
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
//简化下调用链
doTraversal()
-->performTraversals()
-->measureHierarchy
-->performMeasure
-->mView.measure(childWidthMeasureSpec,childHeightMeasureSpec);
//最终触发布局的测量、绘制。setText的流程完成
用一个简单的代码调用顺序图表示,通信用了handler发送消息。
本篇就到此结束。