初探WindowManager

学习自Android源码设计模式

首先看Dialog的构造函数

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
    //获取WindowManager
    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    //创建Window
    final Window w = new PhoneWindow(mContext);
    //把WindowManager设置到Window里去
    w.setWindowManager(mWindowManager, null, null);
}

继续

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
        boolean hardwareAccelerated) {
    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    }
    //创建本地WindowManager,传入自己这个Window
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}

关注WindowImpl.addView

public void addView(View view, Display display, Window parentWindow) {

    ViewRootImpl root;

    synchronized (mLock) {

        root = new ViewRootImpl(view.getContext(), display);

        mViews.add(view);//这些都是ArrayList
        mRoots.add(root);
        mParams.add(wparams);//wparams是由ViewGroup.Params转化而来的Window.params

        try {
            root.setView(view, wparams, panelParentView);//把view设置到ViewRootImpl中
        } catch (RuntimeException e) {
        }
    }
}

ViewRootImpl构造函数

public ViewRootImpl(Context context, Display display) {
    //获取WindowSession,也就是与WMS交互
    mWindowSession = WindowManagerGlobal.getWindowSession();
}

继续

public static IWindowSession getWindowSession() {
    synchronized (WindowManagerGlobal.class) {
        if (sWindowSession == null) {
            try {
                InputMethodManager imm = InputMethodManager.getInstance();
                //获取WMS
                IWindowManager windowManager = getWindowManagerService();
                //建立session
                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;
    }
}

继续

public static IWindowManager getWindowManagerService() {
    synchronized (WindowManagerGlobal.class) {
        if (sWindowManagerService == null) {
            sWindowManagerService = IWindowManager.Stub.asInterface(
                    ServiceManager.getService("window"));//无疑ServiceManager.getService("window")获取的是IBinder
            try {
                if (sWindowManagerService != null) {
                    ValueAnimator.setDurationScale(
                            sWindowManagerService.getCurrentAnimatorScale());
                }
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        return sWindowManagerService;
    }
}

继续

public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if (service != null) {
            return service;
        } else {
            return Binder.allowBlocking(getIServiceManager().getService(name));
        }
    } catch (RemoteException e) {
        Log.e(TAG, "error in getService", e);
    }
    return null;
}

session就是Framework 与c(WMS)的交换信息的场所。

WMS管理当前哪个View应该在最上层显示。

接下去看一看ViewRootImpl.setView,这个方法会向WMS发起显示DecorView的请求

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {
            
            //开始整体绘制
            requestLayout();

            try {
                //向WMS发起请求
                res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(),
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                        mAttachInfo.mOutsets, mInputChannel);
            } catch (RemoteException e) {
            } finally {
            }
}

看一下熟悉的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();
    }
}

继续

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}

继续

void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

        if (mProfile) {
            Debug.startMethodTracing("ViewAncestor");
        }

        performTraversals();

        if (mProfile) {
            Debug.stopMethodTracing();
            mProfile = false;
        }
    }
}

继续

private void performTraversals() {
1.获取Surface对象

2.performMeasure
3.performLayout
4.performDraw
}

在performDraw中,Framework会获取到Surface对象,然后获取它的可绘制区域——>Canvas,然后Framework会在Canvas上绘制。

private void performDraw() {

    try {
        draw(fullRedrawNeeded);
    } finally {
    }
}

draw,这个方法会获取需要绘制的区域,以及判断是否采用GPU绘制(通常情况是CPU绘制,即drawSoftware)

private void draw(boolean fullRedrawNeeded) {

    //获取Surface
    Surface surface = mSurface;

    //绘制需要更新
    if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
        
        if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {

            //GPU绘制(也就是硬件加速)
            mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);

        } else {
       
            //CPU绘制
            if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
                return;
            }
        }
    }

    //ps:动画的重复执行主要是因为这里的代码
    if (animating) {
        mFullRedrawNeeded = true;
        scheduleTraversals();
    }
}

drawSoftware

private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
        boolean scalingRequired, Rect dirty) {

    final Canvas canvas;

    try {
        final int left = dirty.left;
        final int top = dirty.top;
        final int right = dirty.right;
        final int bottom = dirty.bottom;

        //获取指定区域的Canvas,用于Framework绘图
        canvas = mSurface.lockCanvas(dirty);

    } catch (Surface.OutOfResourcesException e) {
    } catch (IllegalArgumentException e) {
    }

    try {
        try 

            //开始绘制
            mView.draw(canvas);

        } finally {
        }
    } finally {
        try {

            //通知SufaceFlinger更新这块区域
            surface.unlockCanvasAndPost(canvas);

        } catch (IllegalArgumentException e) {
    }
    return true;
}

内容绘制完毕后最终请求WMS显示窗口上的内容

需要一个nice的总结:

提一个问题:decor view(主window)何时才会被WindowManagerImpl.addView?

ActivityThread.handleResumeActivity

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;
        ViewRootImpl impl = decor.getViewRootImpl();
        if (impl != null) {
            impl.notifyChildRebuilt();
        }
    }
    if (a.mVisibleFromClient) {
        if (!a.mWindowAdded) {
            a.mWindowAdded = true;
            wm.addView(decor, l);
        } else {
            a.onWindowAttributesChanged(l);
        }
    }
}

wm.addView就是WindowManagerImpl.addView,在这里你的decor view会被添加到WindowManagerGlobal的mViews集合中去。

也是从这里,开始绘制了。

WindowManagerGlobal.setView

root = new ViewRootImpl(view.getContext(), display);

view.setLayoutParams(wparams);

mViews.add(view);
mRoots.add(root);
mParams.add(wparams);

// do this last because it fires off messages to start doing things
try {
    root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
    // BadTokenException or InvalidDisplayException, clean up.
    if (index >= 0) {
        removeViewLocked(index, true);
    }
    throw e;
}

和之前分析的代码几乎一样了。。。

ViewRootImpl.setView中除了requestLayout,还给WMS打了一个信号,那是什么信号?
把让WMS把我这个Window添加到屏幕中去。

(其实上面笔误了,是WindowManagerImpl.addView。还有图中的获取session,这个步骤应该在 new ViewRootImpl(...)里的)

猜你喜欢

转载自blog.csdn.net/qq_36523667/article/details/81123527
今日推荐