WindowManager在系统中的作用

addView过程
https://blog.csdn.net/u011228598/article/details/86499975

https://www.jianshu.com/p/11e373a91b95

https://www.cnblogs.com/mingfeng002/p/10948732.html

onCreate中xml是如何加到视图中显示的

    /**
     * Set the activity content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the activity.
     *
     * @param layoutResID Resource ID to be inflated.
     * 
     * @see #setContentView(android.view.View)
     * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
     */
    public void setContentView(int layoutResID) {
        getWindow().setContentView(layoutResID);
        initActionBar();
    }

getWindow()获取一个Window
Window是一个抽象类,具体代码如下

    private Window mWindow;

    mWindow = PolicyManager.makeNewWindow(this);

    // The static methods to spawn new policy-specific objects
    public static Window makeNewWindow(Context context) {
        return sPolicy.makeNewWindow(context);
    }
    
    private static final String POLICY_IMPL_CLASS_NAME =
        "com.android.internal.policy.impl.Policy";

    private static final IPolicy sPolicy;

    static {
        // Pull in the actual implementation of the policy at run-time
        try {
            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
            sPolicy = (IPolicy)policyClass.newInstance();
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);
        } catch (InstantiationException ex) {
            throw new RuntimeException(
                    POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(
                    POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
        }
    }
    
    //frameworks/base/policy/src/com/android/internal/policy/impl/Policy.java
    public Window makeNewWindow(Context context) {
        return new PhoneWindow(context);
    }

mWindow实际上是PhoneWindow
newInstance和New有什么区别
从newInstance的注释上看,返回class表示类的新实例,通过调用默认参数(即零参数)构造函数创建
接下来看PhoneWindow

    @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }

    frameworks/base/core/java/android/view/LayoutInflater.java
    /**
     * Inflate a new view hierarchy from the specified xml resource. Throws
     * {@link InflateException} if there is an error.
     * 
     * @param resource ID for an XML layout resource to load (e.g.,
     *        <code>R.layout.main_page</code>)
     * @param root Optional view to be the parent of the generated hierarchy.
     * @return The root View of the inflated hierarchy. If root was supplied,
     *         this is the root View; otherwise it is the root of the inflated
     *         XML file.
     */
    public View inflate(int resource, ViewGroup root) {
        return inflate(resource, root, root != null);
    }
    
    /**
     * Inflate a new view hierarchy from the specified xml resource. Throws
     * {@link InflateException} if there is an error.
     * 
     * @param resource ID for an XML layout resource to load (e.g.,
     *        <code>R.layout.main_page</code>)
     * @param root Optional view to be the parent of the generated hierarchy (if
     *        <em>attachToRoot</em> is true), or else simply an object that
     *        provides a set of LayoutParams values for root of the returned
     *        hierarchy (if <em>attachToRoot</em> is false.)
     * @param attachToRoot Whether the inflated hierarchy should be attached to
     *        the root parameter? If false, root is only used to create the
     *        correct subclass of LayoutParams for the root view in the XML.
     * @return The root View of the inflated hierarchy. If root was supplied and
     *         attachToRoot is true, this is root; otherwise it is the root of
     *         the inflated XML file.
     */
    public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
        if (DEBUG) System.out.println("INFLATING from resource: " + resource);
        XmlResourceParser parser = getContext().getResources().getLayout(resource);//对xml进行解析
        try {
            return inflate(parser, root, attachToRoot);//添加视图
        } finally {
            parser.close();
        }
    }

对比使用代码添加视图是否有重叠的部分
举例添加一个Button
新建布局
设置位置
新建一个控件
添加控件到布局

    /**
     * Adds a child view with the specified layout parameters.
     *
     * <p><strong>Note:</strong> do not invoke this method from
     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
     *
     * @param child the child view to add
     * @param params the layout parameters to set on the child
     */
    public void addView(View child, LayoutParams params) {
        addView(child, -1, params);
    }
    
    /**
     * Adds a child view with the specified layout parameters.
     *
     * <p><strong>Note:</strong> do not invoke this method from
     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
     *
     * @param child the child view to add
     * @param index the position at which to add the child
     * @param params the layout parameters to set on the child
     */
    public void addView(View child, int index, LayoutParams params) {
        if (DBG) {
            System.out.println(this + " addView");
        }

        // addViewInner() will call child.requestLayout() when setting the new LayoutParams
        // therefore, we call requestLayout() on ourselves before, so that the child's request
        // will be blocked at our level
        requestLayout();
        invalidate(true);
        addViewInner(child, index, params, false);
    }

addView有很多重载的方法,最终都调用的三个参数的方法,有一段代码是先刷新然后加载,注释给了解释
设置新的LayoutParams时,addViewInner()将调用child.requestLayout()

在回到inflate()方法上

    public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)
       ...
       
       if (root != null && attachToRoot) {
            root.addView(temp, params);
       }
        
        ...
    }

和使用代码添加布局是一条路,使用资源文件多了解析的步骤
root是PhoneWindow传递来的

    // This is the view in which the window contents are placed. It is either
    // mDecor itself, or a child of mDecor where the contents go.
    private ViewGroup mContentParent;

注释解释为mDecor,应该是Activity的父级视图,从View的层次结构上看,属于DecorView的下的Content
下面来看AddView的流程,应该和视图View对子视图的描述一致吧,暂时不继续往下研究了,后续和View的绘制流程一起理解

再从WindowManager的addView来看

WindowManagerGlobal.java

    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);
        }

        // 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.
            synchronized (mLock) {
                final int index = findViewLocked(view, false);
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
            }
            throw e;
        }
    }

ViewRootImpl.java

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
            	//...
            	
                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                requestLayout();
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    mInputChannel = new InputChannel();
                }
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, 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();
                    }
                }
            }
        }
    }

Window的本质也是View
WindowManager和WindowManagerService(WMS)的联系,关联Surface

    WindowManager mWindowManager = (WindowManager) mContext
                .getSystemService(Context.WINDOW_SERVICE)
    mWindowManager.addView(mView, params);

getSystemService返回new WindowManagerImpl()
addView在当前Activity的Window上添加视图,addWindow则是创建一个新的Window
WindowManagerService负责管理所有的Window

Activity中的Window和WindowManager和Activity中获取的WindowManager还不一样

activity的本质上是一个Window,所有的window是View显示的载体,View绘制到屏幕上
下面分析addview的过程

	root = new ViewRootImpl(view.getContext(), display);
	view.setLayoutParams(wparams);
	mViews.add(view);
	mRoots.add(root);
	mParams.add(wparams);

View的绘制流程概述?

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    	 requestLayout();
    	 
	    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
		                            getHostVisibility(), mDisplay.getDisplayId(),
		                            mAttachInfo.mContentInsets, mInputChannel);
    }

Binder调用WMS的addWindow()

    @Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets,
            InputChannel outInputChannel) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outInputChannel);
    }
    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, InputChannel outInputChannel) {
	//具体操作是否新建一个Window一样
	}

View的绘制流程如下 4.4 和 5.0还不一样

WMS如何管理所有Window

Activity

	private Window mWindow;

	private WindowManager mWindowManager;
	...
    mWindow = PolicyManager.makeNewWindow(this);//PhoneWindow
    ...
	mWindow.setWindowManager(
			(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
			mToken, mComponent.flattenToString(),
			(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
	...
    mWindowManager = mWindow.getWindowManager();
    ...
    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);
    }
    
   public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }
    

WindowManager有两个构造函数

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

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

在回到addWindow方法上

win = new WindowState(this, session, client, token,
		attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);

Window窗口尺寸的计算
Window窗口的绘制关联SurfaceFlinger

https://www.jianshu.com/p/9da7bfe18374
Activity的创建流程中
参考View的绘制流程

ViewRootImp performTraversals 分发到View进行绘制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值