Android WindowManagerService解析(2)

一、Activity背后的Window

每个Activity都对应一个Window,Activity并不是UI真实的载体,真实载体是Activity中的Window。

Activity.java

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) {
    // 1、创建Window
    mWindow = PolicyManager.makeNewWindow(this);
    mWindow.setCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
        mWindow.setSoftInputMode(info.softInputMode);
    }
    if (info.uiOptions != 0) {
        mWindow.setUiOptions(info.uiOptions);
    }
    // 2、创建WindowManager,并将其设置到Window中
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    if (mParent != null) {
        mWindow.setContainer(mParent.getWindow());
    }
    mWindowManager = mWindow.getWindowManager();
}

public Window getWindow() {
    return mWindow;
}

在Activity实例化之后,会调用attach方法,这个方法是Activity最早的一个回调方法,可以看到在这个里面对Window进行了创建。

PolicyManager.java

public final class PolicyManager {
    private static final String POLICY_IMPL_CLASS_NAME =
        "com.android.internal.policy.impl.Policy";

    private static final IPolicy sPolicy;

    static {
        Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
        sPolicy = (IPolicy)policyClass.newInstance();
    }

    public static Window makeNewWindow(Context context) {
        return sPolicy.makeNewWindow(context);
    }
}

public class Policy implements IPolicy {
    private static final String TAG = "PhonePolicy";

    public Window makeNewWindow(Context context) {
        return new PhoneWindow(context);
    }
}

可以看到,创建的是一个PhoneWindow实例,Window是一个抽象类,PhoneWindow继承了Window类。

既然Window是UI的载体,那么我们通常在Activity中执行setContentView方法,莫非真实执行是在Window里面,没错,你猜对了,下面我们来看看。

public void setContentView(int layoutResID) {
    getWindow().setContentView(layoutResID);
    initActionBar();
}

哈哈,看到没有,getWindow方法返回的就是前面创建的PhoneWindow对象,所以,setContentView的真正执行者其实是Window对象。

下面看看PhoneWindow的setContentView方法。

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

这个其实创建一个DecorView,DecorView是一个ViewGroup,然后将我们的View添加到这个DecorView中。

这里写图片描述

二、Window的大管家WindowManager

在Window的身边,有一个得力的管家就是WindowManager,它帮助Window完成各项显示操作。WindowManager的实例化也在Activity的attach方法中。

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) {
    // 1、创建Window
    mWindow = PolicyManager.makeNewWindow(this);
    mWindow.setCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
        mWindow.setSoftInputMode(info.softInputMode);
    }
    if (info.uiOptions != 0) {
        mWindow.setUiOptions(info.uiOptions);
    }
    // 2、创建WindowManager,并将其设置到Window中
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    if (mParent != null) {
        mWindow.setContainer(mParent.getWindow());
    }
    mWindowManager = mWindow.getWindowManager();
}

在第二步中,我们看到通过context.getSystemService(Context.WINDOW_SERVICE)获取到WindowManager对象,然后及其设置到Window对象中,从而实现对Window的管理。

ContextImpl.java

@Override
public Object getSystemService(String name) {
    ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
    return fetcher == null ? null : fetcher.getService(this);
}

从SYSTEM_SERVICE_MAP这个Map中来获取服务代理对象,并且在这之前会将各类服务注册进去。

private static void registerService(String serviceName, ServiceFetcher fetcher) {
    if (!(fetcher instanceof StaticServiceFetcher)) {
        fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
    }
    SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
}

上面是注册方法,下面具体看看WindowService的注册过程

registerService(WINDOW_SERVICE, new ServiceFetcher() {
    Display mDefaultDisplay;
    public Object getService(ContextImpl ctx) {
        Display display = ctx.mDisplay;
        if (display == null) {
            if (mDefaultDisplay == null) {
                DisplayManager dm = (DisplayManager)ctx.getOuterContext().
                        getSystemService(Context.DISPLAY_SERVICE);
                mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
            }
            display = mDefaultDisplay;
        }
        return new WindowManagerImpl(display);
}});

可以看到,我们通过的使用getSystemService(Context.WINDOW_SERVICE)获取得到的是一个WindowManagerImpl对象,并且它并不是一个真正的WindowManagerService的远程代理对象,而是一个对DisplayManagerService远程代理对象的封装。具体可以参考文章 Android WindowManagerService解析(1)

弄清了这个WindowManager之后,我们回过头去看看Window的setWindowManager的过程。

Window.java

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

可以看到,Window中的mWindowManager并且直接使用的前面创建一个WindowManagerImpl对象,而是通过WindowManagerImpl调用createLocalWindowManager来创建的一个WindowManagerImpl对象。

WindowManagerImpl

public final class WindowManagerImpl implements WindowManager {
    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }

}

可以看到,它就是重新创建了一个WindowManagerImpl对象。从这里我们可以知道,在Window中的WindowManager管家是一个WindowManagerImpl对象。

三、UI的显示过程

Window仅仅只是一个载体,真正的显示是由WindowManager来处理的。

下面来看看ActivityThread的handleResumeActivity方法。

ActivityThread.java

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
        boolean reallyResume) {
    ActivityClientRecord r = performResumeActivity(token, clearHide);
    if (r != null) {
        // 1、获取Activity对象
        final Activity a = r.activity;
        // 2、得到Activity的Window对象
        r.window = r.activity.getWindow();
        // 3、拿到Window中的decorView对象
        View decor = r.window.getDecorView();
        decor.setVisibility(View.INVISIBLE);
        // 4、拿到WindowManager对象
        ViewManager wm = a.getWindowManager();
        // 5、得到WindowManger的布局属性
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;
        l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
        l.softInputMode |= forwardBit;
        if (a.mVisibleFromClient) {
            a.mWindowAdded = true;
            // 6、调用WindowManager的addView方法
            wm.addView(decor, l);
        }   
}

看到这里是不是很熟悉,我们平时在使用WindowManager的时候也是这样使用的,这里我们就突然明白原来Activity内部就是封装了一个windowManager,真正使用的还是它的addView方法,这个我们在使用WindowManager经常使用。
这里写图片描述

欢迎关注微信公众号:DroidMind
精品内容独家发布平台


呈现与博客不一样的技术干货

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值