ViewManager、ViewRootImp、WindowManagerImpl、WindowSession等详细解析

Activity 从加载布局文件到显示的过程分析文中最后介绍到,承载了布局文件的DecorView通过ViewManger添加进行显示,那添加之后的显示过程又是怎么样的呢?本篇文章主要分析它接下来显示的过程。

ViewManager WindowManger WindowMangerImpl


activity的makeVisible()还是ActivityThread的handleResumeActivity()函数中,都出现过下面这段代码

     if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
     }

将mDecorView添加到wm中,先来看看ViewManger

public interface ViewManager{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

ViewManger是一个接口,里面包含三个函数的定义,用于添加、删除、更新view
那接下来看看getWindowManger()函数

 public WindowManager getWindowManager() {
        return mWindowManager;
 }

直接返回mWindowManger,那继续查找mWindowManger是在哪里初始化的。

 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) {
        attachBaseContext(context);
        mWindow = new PhoneWindow(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(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初始化
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    }

在activity的attach()方法中对mWindowManager通过mWindow.getWindowManager()获取。那继续看mWindow.getWindowManager()代码

  public WindowManager getWindowManager() {
        return mWindowManager;
    }

也是直接返回mWindowManager,那在Window中查找mWindowManager的初始化

    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

在setWindowManager()中进行初始化,而setWindowManager()函数也是在activity的attach()方法中进行调用的,那我们接着看createLocalWindowManager()

 public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
 }

返回的是WindowManagerImpl对象。
我们回到刚刚触发的地方

 if (!mWindowAdded) {
       ViewManager wm = getWindowManager();
       wm.addView(mDecor, getWindow().getAttributes());
       mWindowAdded = true;
  }

getWindowManager()返回的是一个WindowManagerImpl对象,那么WindowManagerImpl和ViewManger的关系是什么呢?

public final class WindowManagerImpl implements WindowManager {}

WindowManagerImpl实现了WindowManager接口,那我们看WindowManager和ViewManager是什么关系。

public interface WindowManager extends ViewManager {

    public static class BadTokenException extends RuntimeException {
        public BadTokenException() {
        }

        public BadTokenException(String name) {
            super(name);
        }
    }
    public static class InvalidDisplayException extends RuntimeException {
        public InvalidDisplayException() {
        }

        public InvalidDisplayException(String name) {
            super(name);
        }
    }

    public Display getDefaultDisplay();
    public void removeViewImmediate(View view);
      public static class LayoutParams extends ViewGroup.LayoutParams
            implements Parcelable{}

WindowManger继承自ViewManger,WindowManagerImpl实现了WindowManager接口。也就是WindowManagerImpl实现了ViewManger接口,再回到WindowManagerImpl中

public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Display mDisplay;
    private final Window mParentWindow;

    private IBinder mDefaultToken;

    public WindowManagerImpl(Display display) {
        this(display, null);
    }

    private WindowManagerImpl(Display display, Window parentWindow) {
        mDisplay = display;
        mParentWindow = parentWindow;
    }

    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }

    public WindowManagerImpl createPresentationWindowManager(Display display) {
        return new WindowManagerImpl(display, mParentWindow);
    }

    public void setDefaultToken(IBinder token) {
        mDefaultToken = token;
    }

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

    @Override
    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.updateViewLayout(view, params);
    }

    private void applyDefaultToken(@NonNull ViewGroup.LayoutParams params) {
        // Only use the default token if we don't have a parent window.
        if (mDefaultToken != null && mParentWindow == null) {
            if (!(params instanceof WindowManager.LayoutParams)) {
                throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
            }

            // Only use the default token if we don't already have a token.
            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
            if (wparams.token == null) {
                wparams.token = mDefaultToken;
            }
        }
    }

    @Override
    public void removeView(View view) {
        mGlobal.removeView(view, false);
    }

    @Override
    public void removeViewImmediate(View view) {
        mGlobal.removeView(view, true);
    }

    @Override
    public Display getDefaultDisplay() {
        return mDisplay;
    }
}

发现WindowMangerImpl只不过是一个代理类,所有的方法实现都是调用一个WindowManagerGlobal对象。最终的实现都在WindowManagerGlobal中。

转载网上 工匠若水 的一张图片来总结下Window、WindowManger、ViewManger、WindowMangerImpl的关系

这里写图片描述



WindowMangerGlobal


在回到最开始的代码

   if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
     }

wm.addView(mDecor, getWindow().getAttributes());代码最终调用的是WindowMangerGlobal的addView()方法,那我们接下来分析WindowMangerGlobal


    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        ViewRootImpl root;
        View panelParentView = null;
        synchronized (mLock) {
             //初始化ViewRootImpl
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }
        try {
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
        }
    }

在setView()中初始化了一个ViewRootImpl对象,并且将View、LayoutParams添加到了ViewRootImpl,其中还有三个对象mViews、mRoots、mParams,分别保存View(DecorView)、ViewRootImpl以及LayoutParams.

    private final ArrayList<View> mViews = new ArrayList<View>();
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();

其中ViewRootImpl对象是干什么的呢?清楚View的绘制流程的同学应该知道View树的绘制就是从ViewRootImpl开始的,那它还有其他什么作用呢?先来看看代码

public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();
        //省略部分代码
        mWindow = new W(this);
        mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
        mViewVisibility = View.GONE;
        mTransparentRegion = new Region();
        mPreviousTransparentRegion = new Region();
        mAdded = false;
        mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
    }

其中初始化名叫mWindow的变量,已经一个mWindowSession,我们先看WindowManagerGlobal.getWindowSession()


    public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
                try {
                    sWindowManagerService = getWindowManagerService();
                    ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);
                }
            }
            return sWindowManagerService;
        }
    }

    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) {
                    Log.e(TAG, "Failed to open window session", e);
                }
            }
            return sWindowSession;
        }
    }

从上面的代码可以知道,getWindowManagerService()通过Binder机制获取远程WindowManagerService,然后openSession()获取WindowManagerService的WindowSession。ViewRootImpl通过WindowSession单向与WindowManagerService进行通信,然而WindowManagerService也需要与ViewRootImpl进行通信,还记得上面名叫mWindow的W变量吗?WindowManagerService通过W与ViewRootImpl进行单向通信,他们是在哪里产生关联的呢?看setView()函数的代码片段

   try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch

通过mWindowSession.addToDisplay()函数,其中的第一个参数mWindow就是W对象,WindowManagerService通过W与ViewRootImpl进行单向通信。

用一张图来描述W、ViewRootImpl、WindowSession、WindowManagerService的关系

这里写图片描述

至于mView(DecorView)显示到屏幕的过程,设计到Surface、SurfaceFlings、View的绘制流程等细节,将在单独的文章中分析。

发布了29 篇原创文章 · 获赞 16 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览