认识Android中Window(二) 之 Window的内部机制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lyz_zyx/article/details/80868982

简介

我们在上一遍文章《认识Android中Window 之 悬浮窗的使用》中通过悬浮窗和Demo大概知道了Window和WindowManager的使用,今天继续来深入探讨Window的内部机制。如果看过源码的朋友应该知道,Window是一个抽象类,而它的实现是PhoneWindow类。WindowManager类是外界访问Window的入口,WindowManager是一个接口,实现类在WindowManagerImpl类,真实代码在WindowManagerGlobal类。

Android中Window的具体实现位于系统服务WindowManagerService中,它在一个独立的进程,所以WindowManager和WindowManagerService的交互是一个IPC过程。

理解Window 

Android中Window实质上是不存在的,View才是Window存在的实体,或者说View是通过Window来呈现,包括Toast、Dialog以及Activity。拿Activity为例说,每一个Activity都包含一个Window对象,Window对应着一个View和一个ViewRootImpl,ViewRootImpl在之前《View的工作原理》中有提过,View的绘制就是由它来完成的,Window和View通过ViewRootImpl来建立联系。实际上Window是一个抽象基类,它提供了一系列窗口的方法,比如我们常见的:SetContentViewfindViewById等等,而它的唯一实现类则是PhoneWindow。它的部分源码大概是:

public abstract class Window {
……
@Nullable
public View findViewById(@IdRes int id) {
    return getDecorView().findViewById(id);
}
public abstract void setContentView(@LayoutRes int layoutResID);
……
}

理解PhoneWindow

PhoneWindow是唯一实现Window的类,它将DecorView设为根View(DecorView实际上是一个FrameLayout),每个Activity都有一个PhoneWindow对象。PhoneWindow是Activity和View系统交互的桥梁。正如上面所提到的SetContentView方法,其实是通过Activity中间代理了一层,最终还是会调用到PhoneWindow中去。正如以下源码:

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback {
private Window mWindow;
   ……
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) {
  ……
  mWindow = new PhoneWindow(this, window);
  ……
}
……
@Nullable
public View findViewById(@IdRes int id) {
    return getWindow().findViewById(id);
}
public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}
……
public Window getWindow() {
    return mWindow;
}
……
}

可以看到上面方法中都有使用到getWindow()这个方法,这个getWindow()方法获取的就是Activity上的Window。再来看看PhoneWindow部分源码:

public class PhoneWindow extends Window implements MenuBuilder.Callback {

private DecorView mDecor;
……
@Override
public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,  getContext());
        transitionTo(newScene);
    } else {
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
    mContentParentExplicitlySet = true;
}
……
}

请留意installDecor方法那一行,看得出,mContentParent为空时表示当第一次时,当前内容未放置到窗口,便调用了installDecor方法。installDecore方法就是用来添加DecorView根View的。大家可以自行查看installDecore方法,这里就略过了。在接下来通过代码:mLayoutInflater.inflate(layoutResID, mContentParent);的将layoutResID关联的View添加到DecorView中去。最后还有就是通过onContentChanged方法回调通知Activity。

理解WindowManager

WindowManager是外界访问Window的入口,它是一个接口,它继承于ViewManager。负责Window的管理工作,实现类是WindowManagerImpl,而添加、更新、删除这三个对View的操作交由WindowManagerGlobal来处理。

——ViewManager

ViewManager一个接口,它是用来添加和移除activity中View的接口,它定义了一组操作View的方法:add、update、remove。

——WindowManagerImpl

WindowManagerImpl是WindowManager的实现类,实质上它没干什么事情,可以理解成是一个代理,它有一个WindowManagerGlobal的单例对象,所有事情都是由WindowManagerGlobal来处理的。正如部分源码:

public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Context mContext;
    private final Window mParentWindow;
      ……
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.updateViewLayout(view, params);
}
@Override
public void removeView(View view) {
    mGlobal.removeView(view, false);
}
……
}

——WindowManagerGlobal

       WindowManagerGlobal是真正处理View的添加、更新、删除的地方。

理解WindowManagerService

WindowManagerService是一个系统服务,运行在单独的线程中,管理系统中所有的Window,注意是所有。在Window的添加、更新和删除过程中,其实就是WindowManager和WindowManagerService的IPC调用中完成。例如上面WindowManagerImp中addView方法,调用了WindowManagerGlobal的addView方法,下面来看看源码:

public final class WindowManagerGlobal {

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>();
private final ArraySet<View> mDyingViews = new ArraySet<View>();
   ……
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
    ……
    synchronized (mLock) {
            ……
        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) {
        synchronized (mLock) {
            final int index = findViewLocked(view, false);
            if (index >= 0) {
                removeViewLocked(index, true);
            }
        }
        throw e;
    }
}
}

我们先来看看WindowManagerGlobal内部的几个列表对象:

mViews               存储的是所有 Window 所对应的 View

mRoots               存储的是所有 Window 所对应的 ViewRootImpl

mParams            存储的是所有 Window 所对应的布局参数

mDyingViews     存储了那些正在被删除的 View 对象,或者说是那些已经调用了 removeView 方法但是操作删除还未完成的 Window 对象

在addView方法中,其实就是将这些相关对象添加到上面的列表对象中,然后请看try catch中的root.setView(view, wparams, panelParentView);这行代码,这是调用了ViewRootImpl的setView方法。还记得ViewRootImpl在View的工作原理中提过吗?View的绘制就是由它来完成的。接着我们再来看看这个setView方法到底干了些啥事情:

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks {
final IWindowSession mWindowSession;
public ViewRootImpl(Context context, Display display) {
    mContext = context;
    mWindowSession = WindowManagerGlobal.getWindowSession();
    ……
}

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {
          ……
            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 (RemoteException e) {
                mAdded = false;
                mView = null;
                mAttachInfo.mRootView = null;
                mInputChannel = null;
                mFallbackEventHandler.setView(null);
                unscheduleTraversals();
                setAccessibilityFocus(null, null);
                throw new RuntimeException("Adding window failed", e);
            } finally {
                if (restore) {
                    attrs.restore();
                }
            }
            ……
            }
            ……
        }
    }
}
}

以上代码,重点部分还是try catch部分,请看mWindowSession.addToDisplay(…这句代码。这里,mWindowSession是一个IWindowSession接口,它是一个Binder对象,真正的实现类是Session这也就是之前提到的IPC过程,然后在 Session 内部会通过 WindowManagerService的addWindow 来实现 Window 的添加。整个过程, Window 的添加请求移交给 WindowManagerService 手上去处理了 。

总结

通过上述中,对WindowViewRootImpl、PhoneWindowDecorViewWindowManagerWindowManagerImpl 、WindowManagerGlobal、ViewManager和 WindowManagerService的理解,相信大家也对Window的内部机制和Window的添加过程有了一定的了解。其实,更新和删除过程也是跟添加过程类似,也就是一个IPC操作移给WindowManagerService的过程。所以这三种操作过程用流程图表现大概是这样:


猜你喜欢

转载自blog.csdn.net/lyz_zyx/article/details/80868982