Window 窗口

1.什么是Window

  • 1.1、代码层面来看,Window是一个abstract类。
/**
 * Abstract base class for a top-level window look and behavior policy.  An
 * instance of this class should be used as the top-level view added to the
 * window manager. It provides standard UI policies such as a background, title
 * area, default key processing, etc.
 *
 * <p>The only existing implementation of this abstract class is
 * android.view.PhoneWindow, which you should instantiate when needing a
 * Window.
 */
public abstract class Window {
    ...
}
  • 1.2、解释
    • Window是为顶级View提供的一个抽象类,该实现类应该作为顶级的view被添加到WindowManager中
    • WindowManager提供了标准的ui规则,比如:背景,标题等
    • 仅仅有一个存在的实例PhoneWindow,当需要Window时,实例PhoneWindow即可。

2.什么是WindowManager

  • 2.1、直接看WindowManager interface的实现类
/**
 * Provides low-level communication with the system window manager for
 * operations that are bound to a particular context, display or parent window.
 * Instances of this object are sensitive to the compatibility info associated
 * with the running application.
 *
 * This object implements the {@link ViewManager} interface,
 * allowing you to add any View subclass as a top-level window on the screen.
 * Additional window manager specific layout parameters are defined for
 * control over how windows are displayed.  It also implements the {@link WindowManager}
 * interface, allowing you to control the displays attached to the device.
 * 
 * <p>Applications will not normally use WindowManager directly, instead relying
 * on the higher-level facilities in {@link android.app.Activity} and
 * {@link android.app.Dialog}.
 * 
 * <p>Even for low-level window manager access, it is almost never correct to use
 * this class.  For example, {@link android.app.Activity#getWindowManager}
 * provides a window manager for adding windows that are associated with that
 * activity -- the window manager will not normally allow you to add arbitrary
 * windows that are not associated with an activity.
 */
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);
    }

    /**
     * Sets the window token to assign when none is specified by the client or
     * available from the parent window.
     *
     * @param token The default token to assign.
     */
    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;
    }
}
  • 2.2、解释

    • WindowManager 是用来提供低等级的通讯跟system window manager 。例如:绑定context/显示/父Window的操作
    • 允许添加任何的View作为高等级的Window。
    • 一般我们不会直接用WindowManager,通常在Activity、Dialog上使用
  • 2.3、功能

    • addView() 添加View
    • updateViewLayout() 刷新布局
    • applyDefaultToken()
    • removeView()
    • 以上所有操作均是通过单例类 WindowManagerGlobal 完成

3.什么是WindowManagerGlobal

  • 3.1、WindowManagerGlobal是App中全局的窗口管理模块
  • 3.2、WindowManagerGlobal 主要用来与WMS进行交互。
  • 3.3、那么问题来了怎么跟WMS交互?
    • 通过Binder进程间的通信获取WMS的session
public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    // a. 获取WMS
                    IWindowManager windowManager = getWindowManagerService();
                    // b.拉取session
                    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);
                }
            }
            // c.返回WMS中的session
            return sWindowSession;
        }
}

public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                // 进程间通信 binder使用
                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 void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        ...
        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            // Start watching for system 
            // The previous removeView() had not completed executing. Now it has.

            // ...
            // If this is a panel window, then 
            // a.实例该View的ViewRootImpl
            root = new ViewRootImpl(view.getContext(), display);
            // b.设置布局位置参数
            view.setLayoutParams(wparams);
            // c.存储view,ViewRootImpl,params
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }

        // do this last because it fires off messages to start doing things
        // d.将view添加到(显示View)
        root.setView(view, wparams, panelParentView);

    }
  • 3.4、WMS 中的session 存储在了WindowManagerGlobal单例类的实例中,那么如何用到的呢。在addView()中,最后看到 root.setView(view, wparams, panelParentView)了,那么ViewRootImpl到底是什么?

4.什么是ViewRootImpl

// 构造中WindowManagerGlobal.getWindowSession() 获取session
public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();


public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
    mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
    mFallbackEventHandler.setView(view);
    ...
    //a.请求layout
    requestLayout();
    //b.通过session去通知WMS显示mWindow
    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
}

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
       // 检测线程
        checkThread();
        mLayoutRequested = true;
        // 各种通知
        scheduleTraversals();
    }
}

void checkThread() {
        // 只能是当前ViewRootImpl
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    }

void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            // mTraversalRunnable 调用doTraversal()到 performTraversals()中进行View的绘制
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

private void performTraversals() {
    // 各种view change状态检查
    ...
    // measure
   performMeasure(childWidthMeasureSpec, childHeightMeasureSpec)

   // 该dispatchOnGlobalLayout通常用来接收View measure完毕,获取view宽高
   if (triggerGlobalLayoutListener) {
            mAttachInfo.mRecomputeGlobalAttributes = false;
            mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
    }

    ...
    // draw
    performDraw();
}
// dispatchOnGlobalLayout的使用
view.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                //measure完毕
            }
        });
  • 4.1、ViewRootImpl 中获取WindowManagerGlobal中的session,改session 是通过Binder获取WMS中的,在ViewRootImpl进行线程检测、layout,measure,draw等一系列操作。最终ViewRootImpl通过session去通知WMS显示mWindow。

总结

image

猜你喜欢

转载自blog.csdn.net/sinat_24196195/article/details/78927987
今日推荐