美文网首页Android开发Android开发经验谈Android开发
从源码的角度浅谈Activity、Window、View之间的关

从源码的角度浅谈Activity、Window、View之间的关

作者: 24K纯帅豆 | 来源:发表于2018-09-25 17:13 被阅读35次

序言:很多人都会用Activity、Window、View,但是你知道他们是怎样加载出来并呈现在你眼前的吗?你知道他们之间有着鲜为人知的关系吗?

image

讲个很简单的例子,这一天天气甚好,小明外出写生,小明背了一包东西,画板啊,纸啊,笔啊什么的,然后小明找了一处风景甚好的地方,从包里拿出画板,纸,笔然后开始画画,不一会儿小明就画完了一幅风景图。在这个例子当中,画板就好比Activity,纸就好比Window,而笔就是View,我们所看到的就是这幅画,是通过笔一点一点画出来的,在哪里画呢?当然是纸上了,而最终承载这幅画的东西就是画板了。这么说可能不太生动,下面,我们从源码的角度来看看这三者的关系。

Activity的创建过程

我们都知道,Activity启动的时候是从ActivityThread中的Handler中发起的,然后经过handlerLauncher等一系列方法,如果还不知道的话可以去参考我之前写的一步一步带你探索Activity的启动流程

ActivityThread类:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {

    ...
    WindowManagerGlobal.initialize();
    Activity a = performLaunchActivity(r, customIntent);
    ...
}

在这里先调用了WindowManagerGlobal中的初始化方法初始化了WindowManagerService,看名字大概就能知道这是一个WindowManager的服务,通过这个服务可以对页面进行操作;然后通过调用performLaunchActivity方法生成了一个Activity。

Window的创建过程

上面通过performLaunchActivity方法生成了一个Activity,我们来看看是怎样生成的:

ActivityThread类:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

    ...
    Activity activity = null;
    try {
        activity = mInstrumentation.newActivity(cl, 
                component.getClassName(), r.intent);
    } catch (Exception e) {
        ...
    }
    ...
    
    if (activity != null) {
        activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
    }

    ...
}

在这个方法中,通过newActivity这个方法(反射)来生成了一个Activity,生成好了Activity之后就调用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, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback) {
            
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(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);
        }           
}

果然,在Activityattach方法中创建了一个Window,这个Window就是我们经常听到的PhoneWindow

View的创建过程

我们大胆的猜测一下,View应该是被添加到Window中的,那么我们来看一下,到底是怎样添加的呢?上面说到在handlerLauncher中调用了performLaunchActivity方法,源码中还调用了handleResumeActivity方法,这个方法是在生命周期onCreate之后,onResume之前调用的,我们来看一下在这个方法中干了些什么:

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
    
    ...
    r = performResumeActivity(token, clearHide, reason);
    ...
    if (r.window == null && !a.mFinished && willBeVisible) {
         r.window = r.activity.getWindow();
         View decor = r.window.getDecorView();
         decor.setVisibility(View.INVISIBLE);
         ViewManager wm = a.getWindowManager();
         WindowManager.LayoutParams l = r.window.getAttributes();
         a.mDecor = decor;
         
         ...
         wm.addView(decor, l);
         ...
    }           
}

这里会先获取一个WindowDecorView,然后拿到ViewManagerWindowManager的父类),然后调用addView方法,ViewManagerWindowManager都是接口,那么我们只要到他的实现类WindowManagerImpl中去找addView方法就可以了:

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

这个mGlobal就是我们之前的WindowManagerGlobal,看到这里相信大家应该有点眉目了吧,最终是由这货负责把DecorView添加到Window中,在WindowManagerGlobal中的addView方法中还会初始化ViewRootImpl,有兴趣的可以自行看源码了解一下

XML中的View是如何添加到DecorView中的这个也不在这里分析了,可以参考我之前写的一步一步带你解析setContentView源码

总结

啥也不说了,上图

image 公众号:IT先森养成记

相关文章

网友评论

    本文标题:从源码的角度浅谈Activity、Window、View之间的关

    本文链接:https://www.haomeiwen.com/subject/hwmloftx.html