Activity 中 Window 加载显示流程

Window不是视图,但视图是通过Window来添加显示的,上一章简单的分析了一下,我们这一章就看看 Activity 中 Window 的添加流程。 打开一个新 Activity 时,跳转流程比较复杂,本章暂不分析,我们就简单的认为该 Activity 的入口是 ActivityThread 中的 handleLaunchActivity() 方法,从这里分析。

    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity a = performLaunchActivity(r, customIntent);
        if (a != null) {
            ...
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed);
            ...
        }
        ...
    }
这是简化过后的代码,实际上只需要注意上面两个方法就可以,我们先来看看 performLaunchActivity(r, customIntent) 方法

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            ...
        } catch (Exception e) {
            ...
        }
        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                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);
                ...
        }
        ...
        return activity;
    }

这里牵涉一个 Instrumentation 类,该类更像是个中转站,Activity 和 Application 都是在它里面,通过反射创建的, Activity 的生命周期方法回调,也是在它里面调用的,performLaunchActivity()中牵涉 Activity 的生命周期 onCreate() 、 onStart() ,在省略的代码中,有兴趣的可以去读读源码;我们看看列举出来的代码,通过反射方法创建了 activity 对象,然后是 Application,它里面有个逻辑判断,如果 Application 缓存已经存在,则直接返回使用,如果没有,则用反射创建,并缓存起来,接下来就是
activity.attach() 方法,该方法比较重要,需要重点分析一下,省略的部分是Activity 的生命周期回调,不在本文的分析中,看 attach() 方法

Activity:

    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) {
        ...

        mWindow = new PhoneWindow(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        ...

        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();
        mCurrentConfig = config;
    }

首先通过new的方式,创建出一个 PhoneWindow 对象,这里用到了多态,然后设置各种回调事件,回调事件在 Activity 中,重点看看 mWindow.setWindowManager() 方法
Window:
    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);
    }

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

    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }

setWindowManager() 传进去的参数中,context.getSystemService(Context.WINDOW_SERVICE) 获取的对象 wm ,通过上一章可以知道,它已经是 WindowManagerImpl 类型,这里用的是多态写法,方法里为了保险,又做了非空判断,如果为空,重新获取对象,全局通过这个方法获取的是同一个对象,我们注意此方法中最后一行代码 createLocalWindowManager() 方法,它把当前 Window 自身作为参数传进 WindowManagerImpl 的构造方法中,又创建了个新的 WindowManagerImpl 对象。区别是通过 getSystemService(Context.WINDOW_SERVICE) 获取的 WindowManagerImpl 对象中 mParentWindow 参数为 null,而这里新建的 mParentWindow 参数为当前 Window。到这里,感觉好像还没与布局UI扯上关系。前面提到了,performLaunchActivity() 方法中会触发 Activity 的 onCreate() 方法回调,正常情况下,我们会在 onCreate() 中设置自己的UI布局即setContentView(R.layout.activity_layout), Activity 中 
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

getWindow() 是 mWindow对象,PhoneWindow 类型,看看它的方法

    @Override
    public void setContentView(int layoutResID) {
        ...
        if (mContentParent == null) {
            installDecor();
        }
        ...
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }
这是简化后的代码,省略了一些东西,是为了便于理解。

    private DecorView mDecor;
    private ViewGroup mContentParent;
    private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor();
            ...
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
        }
        ...
    }

    protected DecorView generateDecor() {
        return new DecorView(getContext(), -1);
    }

    private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {...}

    public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
    protected ViewGroup generateLayout(DecorView decor) {
        ...
        int layoutResource = R.layout.screen_simple;
        ...
        View in = mLayoutInflater.inflate(layoutResource, null);
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        mContentRoot = (ViewGroup) in;
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        ...
        return contentParent;
    }

一进来就会走入 installDecor() 方法,一开始 mDecor 也为null,创建一个 DecorView,从下面看 DecorView 继承了FrameLayout;mContentParent 此时仍是为null,执行 generateLayout() 方法,该方法中会通过我们Activity的配置,选取对应的 layoutId,我上面写死了 R.layout.screen_simple 布局,通过 LayoutInflater 把它转换为 View,然后添加到 DecorView 中,成为它的子 View,系统中给的 layoutResource 对应的布局,都有一个 id 为 content 的 View,并且是 ViewGroup类型,所以我们可以通过 findViewById 找到它,然后赋值给 mContentParent 对象。继续回到setContentView() 方法中,注意看下一行代码 mLayoutInflater.inflate(layoutResID, mContentParent),这行代码意思是,把layoutResID 转换为 View,同时添加到 mContentParent 中,成为它的子 View,感兴趣的可以看看 LayoutInflater 的源码,到此,layoutResID 对应的布局就成功的添加到了 id 为 content 的ViewGroup 之中,content 本身是 DecorView 的子 View。 接着是一个回调,onContentChanged() 意思是内容布局有变化,它调用的是 Activity 中 onContentChanged() 方法。到此,我们只是把我们的 R.layout.activity_layout 布局添加到了PhoneWindow 中的 mDecor 里面, performLaunchActivity() 方法分析到此为止,我们继续看 handleResumeActivity() 方法。

    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
         ...
        ActivityClientRecord r = performResumeActivity(token, clearHide);
        if (r != null) {
            final Activity a = r.activity;
            ...
            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;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }
            }
            ...
            if (r.activity.mVisibleFromClient) {
                r.activity.makeVisible();
            }
            ...
        } 
    }

    public final ActivityClientRecord performResumeActivity(IBinder token,
            boolean clearHide) {
        ActivityClientRecord r = mActivities.get(token);
        if (r != null && !r.activity.mFinished) {
             ...
            r.activity.performResume();
            ...
        }
        return r;
    }

首先执行 performResumeActivity() 方法,它里面关键的其实就一行代码 r.activity.performResume(),它对应 Activity 的 performResume(),在它里面,判断当前Activity是否需要执行onRestart()、 onStart() 生命周期回调,onResume() 则是必定执行。举个例子,如果打开 A 页面,则会执行 onResume();如果 A 页面里打开了 B 页面,B页面回退到 A 页面,则是onRestart() - onStart() - onResume();这里是第一种情况,只会执行 onResume() 回调。 继续回到 handleResumeActivity() 方法中,看中间的一块代码, View decor = r.window.getDecorView() 中 decor 就是 PhoneWindow 中的 mDecor;decor.setVisibility(View.INVISIBLE) 是让view隐藏;ViewManager wm = a.getWindowManager() 获取到 Activity中的 mWindowManager,实际上是 PhoneWindwo 中的 mWindowManager,就是之前通过 createLocalWindowManager() 方法创建出来的 WindowManagerImpl 对象;l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION 是给 Window 的 type 属性赋值,值为 1,最小的值;接着是 a.mWindowAdded = true; wm.addView(decor, l) 方法,这里是调用WindowManagerImpl 的 addView() 方法添加view,到此就接到上一章的东西了,最终会通过 ActivityManagerService 来添加到窗口上面。看最后的代码 r.activity.makeVisible(),它调用 Activity 的方法

    void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }
由于 handleResumeActivity() 方法中 a.mWindowAdded = true,在这里就把 Activity 中的 mWindowAdded 值赋值为 true,所以 makeVisible() 中只会执行最后一行代码,意思也很明显,就是把 mDecor 由 INVISIBLE 变为 VISIBLE,到此,Activity 中的UI才显示出来。
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值