上一篇文章图像显示深刻学习一:Activity启动过程中介绍了启动一个Activity在整个Android系统中执行的流程,其中能够看到Window的建立,这篇文章就整理一下Window机制的实现过程吧。java
吐个槽,今年大部分时间在公司一直在作SDK项目,UI方面的工做涉及的比较少,如今从新开始作UI了,发现本身对于View方面的知识有点模糊了,后悔之前没有写文章记录下来呀,好记性真的不如烂笔头。session
从新回顾一下图像显示深刻学习一:Activity启动过程文章中的Activity建立过程,应用层经过ApplicationThread.scheduleLaunchActivity(...)
接受远程回调,进而调用ActivityThread.handleLaunchActivity(...)
方法,从而开始了一系列Activity生命周期的回调,而Window的建立显示过程也包含其中,因此咱们仍是从.handleLaunchActivity(...)
该方法开始看起,只摘取出跟Window有关的内容:app
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) { ... WindowManagerGlobal.initialize(); Activity a = performLaunchActivity(r, customIntent); if (a != null) { ... handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason); if (!r.activity.mFinished && r.startsNotResumed) { performPauseActivityIfNeeded(r, reason); ... } }
这里调用了 WindowManagerGlobal.initialize()
方法, WindowManagerGlobal是与WindowManagerService沟通的桥梁,因此这里咱们先看下这个方法到底干了什么:ide
//WindowManagerGlobal.java public static void initialize() { getWindowManagerService(); } public static IWindowManager getWindowManagerService() { synchronized (WindowManagerGlobal.class) { if (sWindowManagerService == null) { sWindowManagerService = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); try { if (sWindowManagerService != null) { ValueAnimator.setDurationScale( sWindowManagerService.getCurrentAnimatorScale()); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return sWindowManagerService; } }
initialize()
方法中使用Binder通讯机制初始化了sWindowManagerService对象,比较简单。回到handleLaunchActivity(...)
中,继续查看performLaunchActivity(...)
:oop
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { //新建Activity activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(); if (r.state != null) { r.state.setClassLoader(cl); } } catch (Exception e) { if (!mInstrumentation.onException(activity, e)) { throw new RuntimeException( "Unable to instantiate activity " + component + ": " + e.toString(), e); } } try { ... if (activity != null) { ... appContext.setOuterContext(activity); //调用attach初始化Activity相关参数 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); ... //调用onCreate回调 if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } ... //调用onStart回调 if (!r.activity.mFinished) { activity.performStart(); r.stopped = false; } //调用onRestoreInstanceState回调 if (!r.activity.mFinished) { if (r.isPersistable()) { if (r.state != null || r.persistentState != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, r.persistentState); } } else if (r.state != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); } } //调用onPostCreate回调 if (!r.activity.mFinished) { activity.mCalled = false; if (r.isPersistable()) { mInstrumentation.callActivityOnPostCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnPostCreate(activity, r.state); } if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onPostCreate()"); } } } ... return activity; }
该方法设计到的Window操做很少,就一个activity.attach(...)
,为了方便,下面把源码贴出来一下:布局
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) { ... mWindow = new PhoneWindow(this, window, activityConfigCallback); mWindow.setWindowControllerCallback(this); mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); ... 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()); } mWindowManager = mWindow.getWindowManager(); mCurrentConfig = config; mWindow.setColorMode(info.colorMode); }
attach(...)
方法中主要作了两件事情:post
mWindow.setWindowManager(....)
会去实例化一个WindowManager实现类WindowManagerImpl:学习
//Window.java public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) { ... mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); } //WindowManagerImpl.java public WindowManagerImpl createLocalWindowManager(Window parentWindow) { return new WindowManagerImpl(mContext, parentWindow); }
PhoneWindow是Window的继承类,每个Window行为都由PhoneWindow执行。好的,接着继续往下看handleResumeActivity(...)
方法:this
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) { ... //回调onResume方法 ... if (!willBeVisible) { try { willBeVisible = ActivityManager.getService().willActivityBeVisible( a.getActivityToken()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } if (r.window == null && !a.mFinished && willBeVisible) { //1. r.window = r.activity.getWindow(); //2. View decor = r.window.getDecorView(); //首先设置DecorView不可见状态 decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); //Window在初始化的时候也会初始化一个LayoutParams,该LayoutParams是一个 //WindowManager.LayoutParams对象 WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; ... if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; //3 wm.addView(decor, l); } ... } } ... //4 if (r.activity.mVisibleFromClient) { ViewManager wm = a.getWindowManager(); View decor = r.window.getDecorView(); wm.updateViewLayout(decor, l); } } r.activity.mVisibleFromServer = true; mNumVisibleActivities++; //5. if (r.activity.mVisibleFromClient) { r.activity.makeVisible(); } } ... }
上面桉序列依次解释代码的逻辑:spa
其中须要解释的是DecorView实例,关于Activity中布局的示意图以下:
能够看到DecorView位于布局的最上游,本质上是一个FrameLayout,那么,DecorView是何时添加进去的呢?答案就是在setContentView(...)
调用的时候,经过在图像显示深刻学习二:setContentView(...)过程分析一文中了解到了DecoView会在setContentView(...)
时候初始化,也就是在onCreate(...)
方法回调以后。
接下来就要着重讲下WindowManager了,WindowManager自己是一个接口类,继承了ViewManager接口,关于ViewManager的定义以下:
public interface ViewManager { //向窗口添加VIew public void addView(View view, ViewGroup.LayoutParams params); //更新窗口中的View public void updateViewLayout(View view, ViewGroup.LayoutParams params); //移除View public void removeView(View view); }
在WindowManager内部中有一个内部静态类LayoutParam,该类实现了Parcelable接口,也就是说提供了序列化的能力,这里先猜想跟Binder通讯有关,下面再进行考证。
WindowManager的实现类为WindowManagerImpl,WindowManagerImpl内部持有了一个WindowManagerGlobal实例,在上面分析中咱们知道WindowManagerGlobal持有了远程WindowManagerService的Binder对象,那么进行Binder通讯确定就经过WindowManagerGlobal进行了,下面看下WindowManagerImpl的主要实现:
public final class WindowManagerImpl implements WindowManager { ... @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); } @Override public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.updateViewLayout(view, params); } @Override public void removeView(View view) { mGlobal.removeView(view, false); } ...
这里的mGlobal就是WindowManagerGlobal对象,能够看到其实WindowManagerImpl也就只是一个代理类,调用ViewManager的方法,实际是调用到了WindowManagerGlobal(WMG)中。接下来就要着重挑一个addView(...)
的研究,在研究以前,先整理一下上面的逻辑:
ApplicationThread.scheduleLaunchActivity(...)
被AMS远程回调后,在会去初始化WindowManagerGlobal与WMS进行沟通的Binder对象。Activity.attach(...)
时候会在内部建立一个PhoneWindow做为Window的实现类。而后回调Activity的onCreate(...)
,onStart(...)
等方法,在onCreate(...)
时候会经过setContentView(...)
建立DecorView。onResume(...)
方法,而后调用WindowManager的addView(...)
以及updateViewLayout(...)
方法。在WMG中有三个变量须要注意一下:
//记录全部Windowsd对应的View private final ArrayList<View> mViews = new ArrayList<View>(); //记录mViews中对应的ViewRootImpl private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>(); //记录全部Window对应的Param private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>(); //记录正在被删除的Views private final ArraySet<View> mDyingViews = new ArraySet<View>();
好的接下来看下WMG的addView(...)
方法:
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { //判空 ... final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; ... ViewRootImpl root; View panelParentView = null; ... //新建ViewRootImpl类 root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); //1 mViews.add(view); mRoots.add(root); mParams.add(wparams); // do this last because it fires off messages to start doing things try { //2 root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. if (index >= 0) { removeViewLocked(index, true); } throw e; } } }
上面代码首先在三个变量作添加对应DecorView变量的信息,而后调用第2步代码(root是一个ViewRootImpl对象,该类掌管着View的测量,布局以及绘图的主要逻辑):
... mWindowSession = WindowManagerGlobal.getWindowSession(); ... public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { mView = view; ...//1 requestLayout(); ... //2 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); } catch (RemoteException e) { mAdded = false; mView = null; mAttachInfo.mRootView = null; mInputChannel = null; mFallbackEventHandler.setView(null); unscheduleTraversals(); setAccessibilityFocus(null, null); throw new RuntimeException("Adding window failed", e); } finally { ... }
上面省略了大部分的代码,步骤1首先看调用了requestLayout()
方法,咱们在平常中使用的requestLayout()
方法其实到最后就是调用ViewRootImpl的requestLayout()
方法:
@Override public void requestLayout() { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; scheduleTraversals(); } } void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } }
这里涉及到Choreographer(编舞者)类,简单来就是使用Handler进行post(...)
操做,因为Handler以及消息队列机制的缘由,该post(...)
须要在咱们执行完ActivityThread.handleLaunchActivity(....)
才能执行,也就是说窗口添加完毕了,post(...)
才会调用,因此等咱们下面分析完再回过头了分析这个。
步骤2主要工做就是在于跟WMS进行通讯,经过调用mWindowSession.addToDisplay(...)
方法,mWindowSession是一个IWindowSession,通常出现I字开头的在系统层代码中都表明着有Binder支持的进程通信能力,咱们看下该类怎么得到到的:
//WindowManagerGlobal.java public static IWindowSession getWindowSession() { synchronized (WindowManagerGlobal.class) { if (sWindowSession == null) { try { InputMethodManager imm = InputMethodManager.getInstance(); IWindowManager windowManager = getWindowManagerService(); sWindowSession = windowManager.openSession( new IWindowSessionCallback.Stub() { @Override public void onAnimatorScaleChanged(float scale) { ValueAnimator.setDurationScale(scale); } }, imm.getClient(), imm.getInputContext()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return sWindowSession; } }
经过WMS对象打开一个Session,每一个Session是一个Window的Native的代理类,WMS经过掌管不一样的Session与应用层的Window进行通讯:
//WindowManagerService.java @Override public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client, IInputContext inputContext) { if (client == null) throw new IllegalArgumentException("null client"); if (inputContext == null) throw new IllegalArgumentException("null inputContext"); Session session = new Session(this, callback, client, inputContext); return session; }
接下来继续看mWindowSession.addToDisplay(...)
方法在Native层的调用的:
//Session.java @Override public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outContentInsets, outStableInsets, outOutsets, outInputChannel); }
Seesion中从新调回WMS在addWindow(...)
方法:
public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { int[] appOp = new int[1]; //检察权限 int res = mPolicy.checkAddPermission(attrs, appOp); if (res != WindowManagerGlobal.ADD_OKAY) { return res; } ... final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId); ... //判断Window合法性 ... ... res = WindowManagerGlobal.ADD_OKAY; ... return res; }
改代码中建立一个DisplayContent以及WindowState(真正表示一个Native Window与应用层对应),这些主要跟Surface有关,这里就先不分析了,到时候写一篇关于Surface的文章再作记录。最终返回WindowManagerGlobal.ADD_OKAY。
ok到此Window在Native的添加已经完毕,那咱们接着返回查看ViewRootImpl.setView(...)
方法中的requestLayout(...)
方法。上面讲到该方法最终调用到mTraversalRunnable实例中,那么看下该Runnable对象干了什么东东:
final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } }
这里调用doTraversal()
方法,该方法最终又调用performTraversals()
方法,该方法就是最终管理View的测量,布局,绘图的最顶层方法:
private void performTraversals() { // cache mView since it is used so much below... final View host = mView; ... //赋值系统Window的宽高 int desiredWindowWidth; int desiredWindowHeight; ... relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); ... //测量 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); ... //布局 performLayout(lp, mWidth, mHeight); ... //绘图 performDraw(); ... }
首先这里有relayoutWindow(params, viewVisibility, insetsPending)
操做,该方法内部会建立一个Surface对象与ViewRootImpl关联起来,这里作个笔记,下次对Surface分析的时候有用。下面方法主要就是测量,布局,绘图过程了,这里不对测量,布局,绘图过程进行细究了,他们最终依次回调onMeasure(...)
,onLayout(...)
,onDraw(...)
方法。