如何应对Android面试官 -> Window 显示次序,尺寸计算

前言


image.png

本章我们继续上一节讲解 WMS 相关知识点,Window 是如何显示以及尺寸计算;

View 的添加过程


View 的添加过程是有两个地方,一个是在 onResume 的时候,一个是在

onResume

Activity 在创建之后,执行 onResume 的时候,把 View 添加到 WMS,然后由 WMS 交给 SurfaceFinger 进行绘制;

startActivity

在 startActivity 中的 startingWindow 的时候 也会有一个添加窗口的过程;

image.png

在 Window 的显示次序、窗口尺寸的计算,以及与 AMS 的通信等逻辑中有两个重要的概念,一个是 WindowContainerController 一个是 WindowContainer;我们来看下这两个重要的概念;

WindowContainer


/**
 * Defines common functionality for classes that can hold windows directly or through their
 * children in a hierarchy form.
 * The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime
 * changes are made to this class.
 */
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
        implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable {
} 

可以看下它的定义:主要是用来实现 window 显示次序;它继承了 ConfigurationContainer 这个类,这个类主要是手机的一些设置,它也实现了 Comparable 接口,用来进行排序的,也就是控制显示次序;我们来看下它的 compareTo 方法的具体实现;

public int compareTo(WindowContainer other) {
    if (this == other) {
        return 0;
    }

    if (mParent != null && mParent == other.mParent) {
        final WindowList<WindowContainer> list = mParent.mChildren;
        return list.indexOf(this) > list.indexOf(other) ? 1 : -1;
    }

    final LinkedList<WindowContainer> thisParentChain = mTmpChain1;
    final LinkedList<WindowContainer> otherParentChain = mTmpChain2;
    try {
        getParents(thisParentChain);
        other.getParents(otherParentChain);

        // Find the common ancestor of both containers.
        WindowContainer commonAncestor = null;
        WindowContainer thisTop = thisParentChain.peekLast();
        WindowContainer otherTop = otherParentChain.peekLast();
        while (thisTop != null && otherTop != null && thisTop == otherTop) {
            commonAncestor = thisParentChain.removeLast();
            otherParentChain.removeLast();
            thisTop = thisParentChain.peekLast();
            otherTop = otherParentChain.peekLast();
        }

        // Containers don't belong to the same hierarchy???
        if (commonAncestor == null) {
            throw new IllegalArgumentException("No in the same hierarchy this="
                    + thisParentChain + " other=" + otherParentChain);
        }

        // Children are always considered greater than their parents, so if one of the containers
        // we are comparing it the parent of the other then whichever is the child is greater.
        if (commonAncestor == this) {
            return -1;
        } else if (commonAncestor == other) {
            return 1;
        }

        // The position of the first non-common ancestor in the common ancestor list determines
        // which is greater the which.
        final WindowList<WindowContainer> list = commonAncestor.mChildren;
        return list.indexOf(thisParentChain.peekLast()) > list.indexOf(otherParentChain.peekLast())
                ? 1 : -1;
    } finally {
        mTmpChain1.clear();
        mTmpChain2.clear();
    }
}

当往 WindowContainer 放的时候,就会通过这个方法进行比较,来确定当前这个 window 要插入到什么位置;我们接着来看下 add 方法;

protected void addChild(E child, Comparator<E> comparator) {
    if (!child.mReparenting && child.getParent() != null) {
        throw new IllegalArgumentException("addChild: container=" + child.getName()
                + " is already a child of container=" + child.getParent().getName()
                + " can't add to container=" + getName());
    }

    int positionToAdd = -1;
    if (comparator != null) {
        final int count = mChildren.size();
        for (int i = 0; i < count; i++) {
            // 在这里进行排序的逻辑
            if (comparator.compare(child, mChildren.get(i)) < 0) {
                positionToAdd = i;
                break;
            }
        }
    }

    if (positionToAdd == -1) {
        mChildren.add(child);
    } else {
        mChildren.add(positionToAdd, child);
    }

    // Set the parent after we've actually added a child in case a subclass depends on this.
    child.setParent(this);
}

通过 comparator.compare(child, mChildren.get(i)) < 0 进行比较排序;

image.png

上图是 WindowContainer 的一些衍生类;

而 WindowContainer 又继承自 ConfigurationContainer,整体的一个关系图如下:

infoflow 2024-05-20 12-08-30.png

WindowContainerController


说完 WindowContainer 我们来说一下和它长的比较像的 WindowContainerController 先来上一张继承关系图

infoflow 2024-05-20 12-11-46.png

WindowContainer 和 WindowContainerController 之间的关系

infoflow 2024-05-20 12-13-08.png

系统把 Activity 等都抽象成了 WindowContainer 那么这些 container 需要一些显示逻辑,那么系统就把它们提取出一个 WindowContainerController 在这里面控制它;

就像上图的 Task 对应一个 TaskWindowContainerController,TaskStack 对应一个 StackWindowController;

整体的一个关系图就如下图:

infoflow 2024-05-20 12-20-51.png

通过上图可以看出 DisplayContent -> DisplayWindonwController -> ActivityDisplay -> ActivityRecord 等的这样的一个流程,那么我来看下 ActivityRecord 是怎么创建的;我们先来看下 ActivityDisplay

ActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
    mSupervisor = supervisor;
    mDisplayId = display.getDisplayId();
    mDisplay = display;
    mWindowContainerController = createWindowContainerController();
    updateBounds();
}

这里调用了 createWindowContainerController 它在这里创建了 DisplayWindowController


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值