Android视图加载流程(2)之Window和WindowManager的创建与Activity

Android视图加载流程(1)之SetContent( )

关键接口:ViewManager,WindowManager
关键类:Window,WindowManagerImpl,WindowManagerGlobal
关键方法:ActivityThread.performLaunchActivity() ,Activity.attach();

简单介绍

  1. ViewManager接口定义了一组规则,也就是add、update、remove的操作View接口。
  2. WindowManager接口除了实现ViewManager接口定义的方法外,还定义一些与窗口显示相关的方法。
  3. Window为一个抽象类,提供了绘制窗口的一组通用API
  4. WindowManagerImpl为WindowManager的实现类,一般里面的方法都是具体的实现方法,但它不是!
  5. WindowManagerGlobal是WindowManagerImpl的具体实现类,类似代理,但没有实现同样的接口,且没有继承关系!☆

ViewManager

public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

ViewManagerManager

public interface WindowManager extends ViewManager {
    public static class BadTokenException extends RuntimeException{...}
    public static class InvalidDisplayException extends RuntimeException{...}
    public Display getDefaultDisplay();
    public void removeViewImmediate(View view);
    public static class LayoutParams extends ViewGroup.LayoutParams
    implements Parcelable
}

WindowManagerImpl

public final class WindowManagerImpl implements WindowManager {
    //重点实现类
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Display mDisplay;
    private final Window mParentWindow;
     @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
    ...
     @Override
     public void removeView(View view) {
         mGlobal.removeView(view, false);
     }
}

关系图:

源码解读:

Window是附着于Activity之上的,所以Window的初始化势必与Activity的启动过程有关系!

对于Activity的启动过程,有两种。1. 点击程序进入启动的Activity、2. 已有的Activity中调用startActivty启动。启动期间通过Binder驱动ActivityWindowService,ActivityThread,ApplicationThread,ActivityStack ,Activity之间进行通信,为当前Activity创建进程分配任务栈后启动Activity。

我们直接跳过多个步骤来到与本文章有关系的ActivityThread.handleLaunchActivity去查看Activity的创建

Step1:ActivityThread

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
   ...
    // 在创建Activity前,初始化
    WindowManagerGlobal.initialize();//具体Window的实现类
    
    Activity a = performLaunchActivity(r, customIntent);
    
    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;
        handleResumeActivity(r.token, false, r.isForward,
        ...
}

将WindowManagerGlobal进行初始化,启动Activity。

Step2:ActivityThread

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    Activity activity = null;
    try { 
        //Activity通过ClassLoader创建出来
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);  
    } ...
    try {
        //创建Application
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        ...
        if (activity != null) {
            //创建Activity所需的Context
            Context appContext = createBaseContextForActivity(r, activity);
            ...
            //将Context与Activity进行绑定
            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);
            ...
            //调用activity.oncreate
            mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            ...
            //调用Activity的onstart方法
            activity.performStart();
                //调用activitu的OnRestoreInstanceState方法进行Window数据恢复 
                mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                    r.persistentState);
                ...
        }
    return activity;
}

Step3:Instrumentation

public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
    return (Activity)cl.loadClass(className).newInstance();
}

调用 activity = mInstrumentation.newActivity创建Activity,可以看到里面是通过ClassLoader来加载

Step3: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) {
    //ContextImpl的绑定
    attachBaseContext(context);
    //在当前Activity创建Window
    mWindow = new PhoneWindow(this);
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    ...
    //为Window设置WindowManager
    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());
    }
    //创建完后通过getWindowManager就可以得到WindowManager实例
    mWindowManager = mWindow.getWindowManager();
    mCurrentConfig = config;
}

在Activity的attach方法中,mWindow = new PhoneWindow(this);初始化了Window。并通过 mWindow.setWindowManager将Window于WindowManager进行绑定。且此时mWindow,和mWindowManager成为Activity的成员变量。

Step4:Window

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
        boolean hardwareAccelerated) {
    ...
    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    }
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}

设置WindowManager先判断传入的参数是否为空,为空则通过SystemService获取。最后通过createLocalWindowManager将Window和WindowManager进行绑定。

Step5: Instrumentation

此时我们返回到Step2的mInstrumentation.callActivityOnCreate(activity, r.state ...);

public void callActivityOnCreate(Activity activity, Bundle icicle) {
    prePerformCreate(activity);
    activity.performCreate(icicle);
    postPerformCreate(activity);
}

此方法调用了Activity的performCreate。且在调用之前和调用之后均有做一定的处理操作。

Step6: Activity

final void performCreate(Bundle icicle) {
    onCreate(icicle);//调用熟悉的onCreate
    mActivityTransitionState.readState(icicle);
    performCreateCommon();
}

这已经是我们非常熟悉的onCreate了!

Step7: Activity

此时返回到Step2的activity.performStart();

final void performStart() {
    ...
    mInstrumentation.callActivityOnStart(this);//调用onStart
    ...
    }
}

performStart里调用mInstrumentationcallActivityOnStart(this)

Step8: Instrumentation

public void callActivityOnStart(Activity activity) {
    activity.onStart();//调用熟悉的onStart
}

这已经是我们非常熟悉的onStart了!

Step9: Instrumentation

此时返回到Step2的activity.callActivityOnRestoreInstanceState();

public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) {
    activity.performRestoreInstanceState(savedInstanceState);
}

顾名思义,此方法就是在Activity做数据恢复时调用的方法。

Step10: Activity

final void performRestoreInstanceState(Bundle savedInstanceState) {
    onRestoreInstanceState(savedInstanceState);
    restoreManagedDialogs(savedInstanceState);
}

通过Bundle来保存恢复Window窗口信息,这里就不扩展。

Step11:ActivityThread

此时返回到Step1的handleResumeActivity,由于此方法的东西比较多,在此我们分成4个部分(Part)

final void handleResumeActivity(IBinder token,
        boolean clearHide, boolean isForward, boolean reallyResume) {
    //Part01
    //调用activity.onResume,把activity数据记录更新到ActivityClientRecord
    ActivityClientRecord r = performResumeActivity(token, clearHide);

    //Part02
    if (r != null) {
        final Activity a = r.activity;
        //activity.mStartedActivity是用来标记启动Activity,有没有带返回值,一般我们startActivity(intent)是否默认是startActivityForResult(intent,-1),默认值是-1,所以这里mStartedActivity = false
        boolean willBeVisible = !a.mStartedActivity;
        ...
        //mFinished标记Activity有没有结束,而r.window一开始activity并未赋值给ActivityClientRecord,所以这里为null
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow(); //赋值
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);//默认设置DecorView不可见
            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;
                //把当前的DecorView与WindowManager绑定一起
                wm.addView(decor, l);
            }

        ...
        
        
        if (!r.activity.mFinished && willBeVisible
                && r.activity.mDecor != null && !r.hideForNow) {
                
         //Part03
         //标记当前的Activity有没有设置新的配置参数,比如现在手机是横屏的,而之后你转成竖屏,那么这里的newCofig就会被赋值,表示参数改变
            if (r.newConfig != null) {
                r.tmpConfig.setTo(r.newConfig);
                if (r.overrideConfig != null) {
                    r.tmpConfig.updateFrom(r.overrideConfig);
                }
                //然后调用这个方法回调,表示屏幕参数发生了改变
                performConfigurationChanged(r.activity, r.tmpConfig);
            ...
            WindowManager.LayoutParams l = r.window.getAttributes();
            ...//改变之后update更新当前窗口的DecorView
                if (r.activity.mVisibleFromClient) {
                    ViewManager wm = a.getWindowManager();
                    View decor = r.window.getDecorView();
                    wm.updateViewLayout(decor, l);
                }
            }
            
            //参数没改变
            r.activity.mVisibleFromServer = true;
            mNumVisibleActivities++;
            
            //Part04
            if (r.activity.mVisibleFromClient) {
            //由于前面设置了INVASIBLE,所以现在要把DecorView显示出来了
                r.activity.makeVisible();
            }
        }
        
       //通知ActivityManagerService,Activity完成Resumed
         ActivityManagerNative.getDefault().activityResumed(token);

}

handleResumeActivity方法一开始就调用了activity = performResumeActivity()方法

Part01

public final ActivityClientRecord performResumeActivity(IBinder token,
        boolean clearHide) {
    ActivityClientRecord r = mActivities.get(token);
                ...
            r.activity.mStartedActivity = false;
            r.activity.onStateNotSaved();
            r.activity.mFragments.noteStateNotSaved();
            ...                
            r.activity.performResume();//重点调用
            ...
            r.paused = false;
            r.stopped = false;
            r.state = null;
            r.persistentState = null;

    return r;
}

让Activity调用onResume,与前几部调用OnCreate和OnStart类似。同时把Activity的信息记录在ActivityClientRecord并返回。

Part02

boolean willBeVisible = !a.mStartedActivity;
if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow(); //赋值
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);//默认设置DecorView不可见
                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;
                    //把当前的DecorView与WindowManager绑定一起
                    wm.addView(decor, l);
                }
  • r.window默认为null,由于还没有复制
  • a.mFinished默认为false,a.mFinished表示Activity是否结束
  • a.mStartedActivity默认为false,导致willBeVisible默认为true。activity.mStartedActivity是用来标记启动Activity需不需要带返回值,一般我们startActivity(intent)是默认调用startActivityForResult(intent,-1),默认值是-1,所以这里mStartedActivity = false

理解:

if (requestCode >= 0) {
    mStartedActivity = true;
}
```java    
因为我们现在处于OnResume了,所以DecorView已经创建添加到Window上了(OnCreate调用SetContent)。接着我们将加载好的DecorView与WindowManager通过`wm.addView(decor, l);`绑定在一起。此时的DecorView设置为不可见!

#### Part03
```java
if (!r.activity.mFinished && willBeVisible
                && r.activity.mDecor != null && !r.hideForNow) {
         //标记当前的Activity有没有设置新的配置参数,比如现在手机是横屏的,而之后你转成竖屏,那么这里的newCofig就会被赋值,表示参数改变
            if (r.newConfig != null) {
                r.tmpConfig.setTo(r.newConfig);
                if (r.overrideConfig != null) {
                    r.tmpConfig.updateFrom(r.overrideConfig);
                }
                //然后调用这个方法回调,表示屏幕参数发生了改变
                performConfigurationChanged(r.activity, r.tmpConfig);
            ...
            WindowManager.LayoutParams l = r.window.getAttributes();
            ...
            //改变之后update更新当前窗口的DecorView
                if (r.activity.mVisibleFromClient) {
                    ViewManager wm = a.getWindowManager();
                    View decor = r.window.getDecorView();
                    wm.updateViewLayout(decor, l);
                }
}

标志是否有新的配置,如果有的话更新当前窗口的DecorView

Part04

void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}

如果当前DecorView还未添加到WindwManager的话,则重新添加,最后设置为VISIBLE。此时的DecorView已经显示到屏幕上。

结束 Finish

此时的Activity已经启动,DecorView加载并显示,且与WindowManager进行了绑定。

总结 Summary

当DecorView加载至WindowManager的使用,真正调用的是WindowManagerGlobal.addView()方法。该方法是通过ViewRoot的setView()方法将View传递给WindowManager。ViewRoot实现了View和WindowManager之间的消息传递。

Android视图加载流程(3)之ViewRootImpl的UI刷新机制


PS:本文整理自以下文章,若有发现问题请致邮 caoyanglee92@gmail.com
Hohohong Android窗口机制(三)Window和WindowManager的创建与Activity

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容