一、Window、WindowManager、WMS

1、三者的定义和关系

  • 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);
<span class="hljs-keyword">if</span> (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的<span class="hljs-built_in">set</span>View方法
        root.setView(view, wparams, panelParentView);
    } catch (RuntimeException e) {
        // BadTokenException or InvalidDisplayException, clean up.
        <span class="hljs-keyword">if</span> (index &gt;= 0) {
            removeViewLocked(index, <span class="hljs-literal">true</span>);
        }
        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, <span class="hljs-literal">true</span>);
    View curView = mRoots.get(index).getView();
    //下一步操作
    removeViewLocked(index, immediate);
    <span class="hljs-keyword">if</span> (curView == view) {
        <span class="hljs-built_in">return</span>;
    }

    throw new IllegalStateException(<span class="hljs-string">"Calling with view "</span> + view
            + <span class="hljs-string">" but the ViewAncestor is attached to "</span> + curView);
}

}

private void removeViewLocked(int index, boolean immediate) {
// 获取到对应的 ViewRootImpl
ViewRootImpl root = mRoots.get(index);
View view = root.getView();

<span class="hljs-keyword">if</span> (view != null) {
    InputMethodManager imm = InputMethodManager.getInstance();
    <span class="hljs-keyword">if</span> (imm != null) {
        imm.windowDismissed(mViews.get(index).getWindowToken());
    }
}
//进行下一步操作
boolean deferred = root.die(immediate);
<span class="hljs-keyword">if</span> (view != null) {
    view.assignParent(null);
    <span class="hljs-keyword">if</span> (deferred) {
        mDyingViews.add(view);
    }
}

}

复制代码

2、die

boolean die(boolean immediate) {
    if (immediate && !mIsInTraversal) {
        //(1)如果immediate为true,立即删除
        doDie();
        return false;
    }
<span class="hljs-keyword">if</span> (!mIsDrawing) {
    destroyHardwareRenderer();
} <span class="hljs-keyword">else</span> {
    Log.e(mTag, <span class="hljs-string">"Attempting to destroy the window while drawing!\n"</span> +
            <span class="hljs-string">"  window="</span> + this + <span class="hljs-string">", title="</span> + mWindowAttributes.getTitle());
}
(2)
mHandler.sendEmptyMessage(MSG_DIE);
<span class="hljs-built_in">return</span> <span class="hljs-literal">true</span>;

}

复制代码

(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, <span class="hljs-literal">true</span>);
    ViewRootImpl root = mRoots.get(index);
    //移除之前的LayoutParams
    mParams.remove(index);
    //添加新的LayoutParams
    mParams.add(index, wparams);
    //更新ViewRootImpl,调用scheduleTraversals方法
    root.setLayoutParams(wparams, <span class="hljs-literal">false</span>);
}

}

复制代码

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 进阶解密》

  • Android

    开放手机联盟(一个由 30 多家科技公司和手机公司组成的团体)已开发出 Android,Android 是第一个完整、开放、免费的手机平台。

    293 引用
感谢    赞同    分享    收藏    关注    反对    举报    ...