Android Framework中的addView和addWindow

调用方式

addView

addView方法是用于将视图添加到布局中的方法,通常用于在应用程序级别的布局中动态添加视图。
addView()是ViewGroup类的方法,用于在一个已经存在的父视图中添加一个子视图。它只能在UI线程中调用,因为它会更新UI。

相关代码

代码路径:frameworks/base/core/java/android/view/ViewGroup.java

    /**
     * <p>Adds a child view. If no layout parameters are already set on the child, the
     * default parameters for this ViewGroup are set on the child.</p>
     *
     * <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
     *
     * @see #generateDefaultLayoutParams()
     */
    public void addView(View child) {
    
    
        addView(child, -1);
    }

    /**
     * Adds a child view. If no layout parameters are already set on the child, the
     * default parameters for this ViewGroup are set on the child.
     *
     * <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
     *
     * @see #generateDefaultLayoutParams()
     */
    public void addView(View child, int index) {
    
    
        if (child == null) {
    
    
            throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
        }
        LayoutParams params = child.getLayoutParams();
        if (params == null) {
    
    
            params = generateDefaultLayoutParams();
            if (params == null) {
    
    
                throw new IllegalArgumentException(
                        "generateDefaultLayoutParams() cannot return null  ");
            }
        }
        addView(child, index, params);
    }

    /**
     * Adds a child view with this ViewGroup's default layout parameters and the
     * specified width and height.
     *
     * <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
     */
    public void addView(View child, int width, int height) {
    
    
        final LayoutParams params = generateDefaultLayoutParams();
        params.width = width;
        params.height = height;
        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 params the layout parameters to set on the child
     */
    @Override
    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 or -1 to add last
     * @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");
        }

        if (child == null) {
    
    
            throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
        }

        // 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的调用方式有下面这几种

addView(View child)   // child 被添加的View,默认index为-1
addView(View child, int index)   // index 被添加的View的索引
addView(View child, int width, int height)   // width,height被添加的View指定的宽高,默认index为-1
addView(View view, ViewGroup.LayoutParams params)   // params被添加的View指定的布局参数,默认index为-1
addView(View child, int index, LayoutParams params) 

这些方法最终都会调用到addView(View child, int index, LayoutParams params),其中index的取值范围小于等于1,且为整数
当index为负数时,会一直在最下面的一层添加view;当index=0,就是第一层添加view层;当index=1时,就会在第二层添加view层。
注:其对应的removeView方法同样在ViewGroup中。

调用示例

private LinearLayout mLinearLayout;
mLinearLayout = findViewById(R.id.container);
TextView textView = new TextView(this);
textView.setText("test");
mLinearLayout.addView(textView,-1);

addWindow

addWindow方法是用于将窗口添加到窗口管理器中的方法,通常用于创建系统级别的窗口,例如:悬浮窗、对话框、Toast提示等。
addWindow()是通过WindowManager接口的实现类,WindowManagerImpl的addView方法,逐步调用到WindowManagerService中的addWindow(),用于在屏幕上添加一个新的顶级窗口。它可以在非UI线程中调用,因为它不会更新UI。

相关代码

代码路径:frameworks/base/core/java/android/view/WindowManager.java
代码路径:frameworks/base/core/java/android/view/WindowManagerImpl.java

    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    
    
        applyTokens(params);
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }

WindowManagerImpl实际调用的是WindowManagerGlobal的addView方法
注:其对应的removeView方法同样在WindowManagerImpl中。

调用示例

private WindowManager mWindowManager;
private WindowManager.LayoutParams mLayoutParams;
private CustomViewLayout mCustomViewLayout;//自定义布局
mWindowManager.addView(mCustomViewLayout, mLayoutParams);

addView和addWindow的区别

  1. 使用场景:addView()方法是在已经存在的ViewGroup中添加新的视图,而addWindow()方法是添加一个新的窗口。

  2. 管理对象:addView()方法是对ViewGroup对象进行操作,而addWindow()方法是对WindowManager对象进行操作。

  3. 权限:为了使用addWindow()方法,需要在AndroidManifest.xml文件中添加权限android.permission.SYSTEM_ALERT_WINDOW,否则会抛出SecurityException异常。

  4. 布局位置:addWindow()方法可以更灵活地控制窗口的布局位置,可以通过LayoutParams参数来设置,在屏幕上任意指定位置显示。而addView()方法则是将视图直接添加到ViewGroup中,并按照其布局规则进行显示。

    扫描二维码关注公众号,回复: 17274321 查看本文章
  5. 堆栈管理:addWindow()方法可以创建一个独立的窗口,在应用程序堆栈中单独管理,可以独立于Activity页面进行操作。而addView()方法则只是在现有的Activity视图层级中添加新的视图。

猜你喜欢

转载自blog.csdn.net/yimelancholy/article/details/134424279