Android視圖加載流程(2)之Window和WindowManager的創(chuàng)建與Activity

Android視圖加載流程(1)之SetContent( )

關鍵接口:ViewManager,WindowManager
關鍵類:Window,WindowManagerImpl,WindowManagerGlobal
關鍵方法:ActivityThread.performLaunchActivity() ,Activity.attach();

簡單介紹

  1. ViewManager接口定義了一組規(guī)則,也就是add、update、remove的操作View接口。
  2. WindowManager接口除了實現(xiàn)ViewManager接口定義的方法外,還定義一些與窗口顯示相關的方法。
  3. Window為一個抽象類,提供了繪制窗口的一組通用API
  4. WindowManagerImpl為WindowManager的實現(xiàn)類,一般里面的方法都是具體的實現(xiàn)方法,但它不是!
  5. WindowManagerGlobal是WindowManagerImpl的具體實現(xiàn)類,類似代理,但沒有實現(xiàn)同樣的接口,且沒有繼承關系!☆

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 {
    //重點實現(xiàn)類
    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中調(diào)用startActivty啟動。啟動期間通過Binder驅動ActivityWindowService,ActivityThread,ApplicationThread,ActivityStack ,Activity之間進行通信,為當前Activity創(chuàng)建進程分配任務棧后啟動Activity。

我們直接跳過多個步驟來到與本文章有關系的ActivityThread.handleLaunchActivity去查看Activity的創(chuàng)建

Step1:ActivityThread

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
   ...
    // 在創(chuàng)建Activity前,初始化
    WindowManagerGlobal.initialize();//具體Window的實現(xiàn)類
    
    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創(chuàng)建出來
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);  
    } ...
    try {
        //創(chuàng)建Application
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        ...
        if (activity != null) {
            //創(chuàng)建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);
            ...
            //調(diào)用activity.oncreate
            mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            ...
            //調(diào)用Activity的onstart方法
            activity.performStart();
                //調(diào)用activitu的OnRestoreInstanceState方法進行Window數(shù)據(jù)恢復 
                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();
}

調(diào)用 activity = mInstrumentation.newActivity創(chuàng)建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創(chuàng)建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());
    }
    //創(chuàng)建完后通過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先判斷傳入的參數(shù)是否為空,為空則通過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);
}

此方法調(diào)用了Activity的performCreate。且在調(diào)用之前和調(diào)用之后均有做一定的處理操作。

Step6: Activity

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

這已經(jīng)是我們非常熟悉的onCreate了!

Step7: Activity

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

final void performStart() {
    ...
    mInstrumentation.callActivityOnStart(this);//調(diào)用onStart
    ...
    }
}

performStart里調(diào)用mInstrumentationcallActivityOnStart(this)

Step8: Instrumentation

public void callActivityOnStart(Activity activity) {
    activity.onStart();//調(diào)用熟悉的onStart
}

這已經(jīng)是我們非常熟悉的onStart了!

Step9: Instrumentation

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

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

顧名思義,此方法就是在Activity做數(shù)據(jù)恢復時調(diào)用的方法。

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
    //調(diào)用activity.onResume,把activity數(shù)據(jù)記錄更新到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有沒有設置新的配置參數(shù),比如現(xiàn)在手機是橫屏的,而之后你轉成豎屏,那么這里的newCofig就會被賦值,表示參數(shù)改變
            if (r.newConfig != null) {
                r.tmpConfig.setTo(r.newConfig);
                if (r.overrideConfig != null) {
                    r.tmpConfig.updateFrom(r.overrideConfig);
                }
                //然后調(diào)用這個方法回調(diào),表示屏幕參數(shù)發(fā)生了改變
                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);
                }
            }
            
            //參數(shù)沒改變
            r.activity.mVisibleFromServer = true;
            mNumVisibleActivities++;
            
            //Part04
            if (r.activity.mVisibleFromClient) {
            //由于前面設置了INVASIBLE,所以現(xiàn)在要把DecorView顯示出來了
                r.activity.makeVisible();
            }
        }
        
       //通知ActivityManagerService,Activity完成Resumed
         ActivityManagerNative.getDefault().activityResumed(token);

}

handleResumeActivity方法一開始就調(diào)用了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();//重點調(diào)用
            ...
            r.paused = false;
            r.stopped = false;
            r.state = null;
            r.persistentState = null;

    return r;
}

讓Activity調(diào)用onResume,與前幾部調(diào)用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)是默認調(diào)用startActivityForResult(intent,-1),默認值是-1,所以這里mStartedActivity = false

理解:

if (requestCode >= 0) {
    mStartedActivity = true;
}
```java    
因為我們現(xiàn)在處于OnResume了,所以DecorView已經(jīng)創(chuàng)建添加到Window上了(OnCreate調(diào)用SetContent)。接著我們將加載好的DecorView與WindowManager通過`wm.addView(decor, l);`綁定在一起。此時的DecorView設置為不可見!

#### Part03
```java
if (!r.activity.mFinished && willBeVisible
                && r.activity.mDecor != null && !r.hideForNow) {
         //標記當前的Activity有沒有設置新的配置參數(shù),比如現(xiàn)在手機是橫屏的,而之后你轉成豎屏,那么這里的newCofig就會被賦值,表示參數(shù)改變
            if (r.newConfig != null) {
                r.tmpConfig.setTo(r.newConfig);
                if (r.overrideConfig != null) {
                    r.tmpConfig.updateFrom(r.overrideConfig);
                }
                //然后調(diào)用這個方法回調(diào),表示屏幕參數(shù)發(fā)生了改變
                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已經(jīng)顯示到屏幕上。

結束 Finish

此時的Activity已經(jīng)啟動,DecorView加載并顯示,且與WindowManager進行了綁定。

總結 Summary

當DecorView加載至WindowManager的使用,真正調(diào)用的是WindowManagerGlobal.addView()方法。該方法是通過ViewRoot的setView()方法將View傳遞給WindowManager。ViewRoot實現(xiàn)了View和WindowManager之間的消息傳遞。

Android視圖加載流程(3)之ViewRootImpl的UI刷新機制


PS:本文整理自以下文章,若有發(fā)現(xiàn)問題請致郵 caoyanglee92@gmail.com
Hohohong Android窗口機制(三)Window和WindowManager的創(chuàng)建與Activity

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容