Android 源码解析之WindowManager更新窗口

来源:互联网 发布:git clone ssh 端口 编辑:程序博客网 时间:2024/06/10 04:31

一,写在前面

       在阅读本篇文章前,建议先了解使用WindowManager添加窗口的内部实现原理,可以参考文章Android 源码解析之WindowManager添加窗口。本篇文章将从源码角度解析WindowManager更新窗口,也算是WindowManager添加,删除,更新窗口的完结篇。由于跟添加窗口比较类似,只会简单介绍下代码流程,不再重复介绍一些类,接口等。

二,WindowManager更新窗口

       前面已经讲过,更新窗口实际上是调用WindowManagerImpl$updateViewLayout方法。
       查看WindowManagerImpl$updateViewLayout源码如下:
    @Override    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {        applyDefaultToken(params);        mGlobal.updateViewLayout(view, params);    }
      
       继续查看WindowManagerGlobal$updateViewLayout源码:
    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {        if (view == null) {            throw new IllegalArgumentException("view must not be null");        }        if (!(params instanceof WindowManager.LayoutParams)) {            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");        }        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;        view.setLayoutParams(wparams);        synchronized (mLock) {            int index = findViewLocked(view, true);            ViewRootImpl root = mRoots.get(index);            mParams.remove(index);            mParams.add(index, wparams);            root.setLayoutParams(wparams, false);        }    }
       首先对view,params做一些检查的操作;
       第9行,params向下转型;
       第11行,重新给View设置布局参数params;
       第14行,获取View在集合中的索引位置;
       第15行,根据索引位置index,获取mRoots集合中ViewRootImpl对象;
       第16,17行,替换mParams集合中索引位置的WindowManager.LayoutParams对象;
       第18行,调用ViewRootImpl$setLayoutParams方法,更新窗口;
       上面分析有不能理解的地方,可阅读Android 源码解析之WindowManager添加窗口。

       继续,查看ViewRootImpl$setLayoutParams源码如下:
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {//...codescheduleTraversals();}
       继续,查看ViewRootImpl$scheduleTraversals源码如下:
    void scheduleTraversals() {        if (!mTraversalScheduled) {            mTraversalScheduled = true;            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();            mChoreographer.postCallback(                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);            if (!mUnbufferedInputDispatch) {                scheduleConsumeBatchedInput();            }            notifyRendererOfFramePending();            pokeDrawLockIfNeeded();        }    }
       第7行,Choreographer调用postCallback方法,注册了TraversalRunnable接口。
       查看ViewRootImpl$TraversalRunnable源码如下:
    final class TraversalRunnable implements Runnable {        @Override        public void run() {            doTraversal();        }    }
       继续,查看ViewRootImpl$doTraversal源码:
    void doTraversal() {        if (mTraversalScheduled) {            mTraversalScheduled = false;            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);            if (mProfile) {                Debug.startMethodTracing("ViewAncestor");            }            performTraversals();            if (mProfile) {                Debug.stopMethodTracing();                mProfile = false;            }        }    }
       第10行,调用performTraversals()。
       继续,查看ViewRootImpl$performTraversals源码:
 private void performTraversals() { //...coderelayoutResult = relayoutWindow(params, viewVisibility, insetsPending);//...code }
       继续,查看ViewRootImpl$relayoutWindow源码:
 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,            boolean insetsPending) throws RemoteException {//...codeint 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);    //...code}
       mWindowSession是一个Session对象,获取该Session对象是一次IPC调用。基于Binder机制,完成了一次跟系统服务WindowManagerService的通信。(详细分析见文章Android 源码解析之WindowManager添加窗口)
       查看Session$relayout源码如下:
    @Override    public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,            int requestedWidth, int requestedHeight, int viewFlags,            int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,            Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,            MergedConfiguration mergedConfiguration, Surface outSurface) {        if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "                + Binder.getCallingPid());        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);        int res = mService.relayoutWindow(this, window, seq, attrs,                requestedWidth, requestedHeight, viewFlags, flags,                outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,                outStableInsets, outsets, outBackdropFrame, mergedConfiguration, outSurface);        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);        if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "                + Binder.getCallingPid());        return res;    }
       第10行,mService是WindowManagerService对象,也就是说,更新窗口的操作最终交给了WindowManagerService来处理。
       至于WindowManagerService更新窗口的流程就暂不介绍了,有兴趣的哥们可以参考老罗的博客。

三,总结

       WindowManager添加窗口时,都用ViewRootImp$setView方法(见文章Android 源码解析之WindowManager添加窗口);
       WindowManager删除窗口时,调用ViewRootImp$doDie方法(见文章Android 源码解析之WindowManager删除窗口);
       WindowManager更新窗口时,调用ViewRootImp$setLayoutParams方法;
       不管是添加,删除,更新窗口,都会通过Binder机制获取到Session对象。在Session类的内部,处理窗口的操作都是交给WindowManagerService来处理啦~

       

         





       


阅读全文
0 0
原创粉丝点击