内容简介:三者关系:一个抽象类,其具体实现为PhoneWindowWindowManager继承了ViewManager,ViewManager中定义了添、删、改的方法。
- Window可以理解为窗体,是一种抽象概念,其中具体表现形式就是View。
- WindowManager是用来添加、删除、更新Window(具体是View)的。
- WindowManagerService是在SystemServer进程中的,WindowManger中的所有操作都是由WMS来最终完成的。
三者关系:
2、Window
一个抽象类,其具体实现为PhoneWindow
3、WindowManager
WindowManager继承了ViewManager,ViewManager中定义了添、删、改的方法。
public interface ViewManager { public void addView(View view, ViewGroup.LayoutParams params); public void updateViewLayout(View view, ViewGroup.LayoutParams params); public void removeView(View view); } 复制代码
4、Activity中PhoneWindow的创建
在Activity启动过程中,执行到了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) { attachBaseContext(context); mFragments.attachHost(null /*parent*/); //实现了PhoneWindow的创建 mWindow = new PhoneWindow(this, window, activityConfigCallback); mWindow.setWindowControllerCallback(this); //设置回调 mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); ...... //(1)设置WindowManager 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); } 复制代码
(1)context.getSystemService(Context.WINDOW_SERVICE)获取的是什么?
Context具体实现在ContextImpl中
#ContextImpl @Override public Object getSystemService(String name) { return SystemServiceRegistry.getSystemService(this, name); } #SystemServiceRegistry public static Object getSystemService(ContextImpl ctx, String name) { ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name); return fetcher != null ? fetcher.getService(ctx) : null; } 复制代码
SYSTEM_SERVICE_FETCHERS是一个map,key为WINDOW_SERVICE时,对应的value是什么?
#SystemServiceRegistry registerService(Context.WINDOW_SERVICE, WindowManager.class, new CachedServiceFetcher<WindowManager>() { @Override public WindowManager createService(ContextImpl ctx) { return new WindowManagerImpl(ctx); }}); 复制代码
注册服务时,传入Context.WINDOW_SERVICE时,最终返回的是WindowManagerImpl。
public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) { ...... if (wm == null) { wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); } mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); } 复制代码
通过createLocalWindowManager,最终创建了WindowManagerImpl对象。
二、Activity中Window添加
1、ActivityThread的handleResumeActivity
当界面要与用户进行交互时,需要调用handleResumeActivity方法
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) { ...... (1) //最终调用Activity的onResume r = performResumeActivity(token, clearHide, reason); ...... if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (r.mPreserveWindow) { a.mWindowAdded = true; r.mPreserveWindow = false; // Normally the ViewRoot sets up callbacks with the Activity // in addView->ViewRootImpl#setView. If we are instead reusing // the decor view we have to notify the view root that the // callbacks may have changed. ViewRootImpl impl = decor.getViewRootImpl(); if (impl != null) { impl.notifyChildRebuilt(); } } if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; (2) wm.addView(decor, l); } ...... } } 复制代码
(2)最终调用了WindowManagerImpl的addView方法
2、WindowManager的addView
#WindowManagerImpl @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); } 复制代码
内部调用WindowManagerGlobal的addView方法
3、WindowManagerGlobal
(1)部分参数:
//Window所对应的view private final ArrayList<View> mViews = new ArrayList<View>(); //Window所对应的ViewRootImpl private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>(); //Window所对应的布局参数 private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>(); //已经调用了removeView,但是还没完成的Window对象 private final ArraySet<View> mDyingViews = new ArraySet<View>(); 复制代码
(2)addView方法
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { ...... //创建ViewRootImpl root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); //将参数添加到list中 mViews.add(view); mRoots.add(root); mParams.add(wparams); 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的setView方法
#ViewRootImpl public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { ...... (1) requestLayout(); ...... try { mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); (2) res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); } ...... } } } 复制代码
(1)通过调用requestLayout,最终通过performTraversals方法完成View的测量、布局、绘制操作。
(2)调用了IWindowSession的addToDisplay方法,IWindowSession实现是什么?
IWindowSession是Binder对象,最终调用的是SystemServer进程的Session的addToDisplay方法
#Session @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); } 复制代码
调用了WMS的addWindow方法,其中使用list将Session进行保存,并为窗口分配画布Surface,用来显示页面,并确定窗口的显示次序。
时序图:
三、WindowManager删除View
1、WindowManagerGlobal的removeView
WindowManager的removeView方法,最终同样调用了WindowManagerGlobal的removeView方法
#WindowManagerGlobal public void removeView(View view, boolean immediate) { if (view == null) { throw new IllegalArgumentException("view must not be null"); } synchronized (mLock) { //找到view对应的索引位置 int index = findViewLocked(view, true); View curView = mRoots.get(index).getView(); //下一步操作 removeViewLocked(index, immediate); if (curView == view) { return; } throw new IllegalStateException("Calling with view " + view + " but the ViewAncestor is attached to " + curView); } } private void removeViewLocked(int index, boolean immediate) { //获取到对应的ViewRootImpl ViewRootImpl root = mRoots.get(index); View view = root.getView(); if (view != null) { InputMethodManager imm = InputMethodManager.getInstance(); if (imm != null) { imm.windowDismissed(mViews.get(index).getWindowToken()); } } //进行下一步操作 boolean deferred = root.die(immediate); if (view != null) { view.assignParent(null); if (deferred) { mDyingViews.add(view); } } } 复制代码
2、die
boolean die(boolean immediate) { if (immediate && !mIsInTraversal) { //(1)如果immediate为true,立即删除 doDie(); return false; } if (!mIsDrawing) { destroyHardwareRenderer(); } else { Log.e(mTag, "Attempting to destroy the window while drawing!\n" + " window=" + this + ", title=" + mWindowAttributes.getTitle()); } (2) mHandler.sendEmptyMessage(MSG_DIE); return true; } 复制代码
(1)同步删除直接调用doDie方法
(2)异步删除通过Handler发送了MSG_DIE的消息,没有真正删除。只是将view添加到一个待删除的列表mDyingViews中
void doDie() { ...... if (mAdded) { //(1)下一步删除操作 dispatchDetachedFromWindow();//5 } ...... //(2) WindowManagerGlobal.getInstance().doRemoveView(this); } 复制代码
(1)调用了Session的remove方法,最终交给WMS进行处理。
void dispatchDetachedFromWindow() { ... try { mWindowSession.remove(mWindow); } catch (RemoteException e) { } ... } 复制代码
(2)将该view对应索引在list中删除
void doRemoveView(ViewRootImpl root) { synchronized (mLock) { final int index = mRoots.indexOf(root); if (index >= 0) { //将该view对应索引在list中删除 mRoots.remove(index); mParams.remove(index); final View view = mViews.remove(index); mDyingViews.remove(view); } } if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) { doTrimForeground(); } } 复制代码
四、WindowManager更新View
1、WindowManagerGlobal的updateViewLayout
#WindowManagerGlobal public void updateViewLayout(View view, ViewGroup.LayoutParams params) { ...... final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; //更新view的LayoutParams view.setLayoutParams(wparams); synchronized (mLock) { //找到view索引 int index = findViewLocked(view, true); ViewRootImpl root = mRoots.get(index); //移除之前的LayoutParams mParams.remove(index); //添加新的LayoutParams mParams.add(index, wparams); //更新ViewRootImpl,调用scheduleTraversals方法 root.setLayoutParams(wparams, false); } } 复制代码
2、ViewRootImpl的setLayoutParams
#ViewRootImpl
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) { synchronized (this) { ...... scheduleTraversals(); } } void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); //注册了TraversalRunnable mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } } final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } } void doTraversal() { if (mTraversalScheduled) { ...... performTraversals(); ...... } } private void performTraversals() { ...... relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); ...... } private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending) throws RemoteException { ...... int relayoutResult = mWindowSession.relayout( mWindow, mSeq, params, (int) (mView.getMeasuredWidth() * appScale + 0.5f), (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets, mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingMergedConfiguration, mSurface); ...... return relayoutResult; } 复制代码
最终通过Session的relayout方法实现view的更新
参考资料:
- 《Android开发艺术探索》
- 《Android进阶解密》
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。