1.Window WindowManager WindowManagerService

啟動(dòng)一個(gè)Activity
startActivity
最終會(huì)走到ActivityThread的performLaunchActivity
這個(gè)函數(shù)里面會(huì)經(jīng)過層層深入會(huì)調(diào)用 Activity 的 OnCreate() 方法判导,而在 performLaunchActivity() 中調(diào) OnCreate() 方法前會(huì)調(diào)用 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, IBinder assistToken) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
      //創(chuàng)建PhoneWindow嫉父,并設(shè)置回調(diào)
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(mWindowControllerCallback);
        mWindow.setCallback(this);
        
        //將window跟windowmanager綁定

        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
       
        //設(shè)置管理window的windowmanager
        mWindowManager = mWindow.getWindowManager();
        

繼續(xù)看Window源碼setWindowManager

/**
     * Set the window manager for use by this Window to, for example,
     * display panels.  This is <em>not</em> used for displaying the
     * Window itself -- that must be done by the client.
     *
     * @param wm The window manager for adding new windows.
     */
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated;
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

這里沒有理解清楚是如何獲取wms
該方法里面可以看到如果傳入的 wm 為空則將其重新賦值。這里其實(shí)是獲取了 WindowManagerService 的代理眼刃,因?yàn)?WindowManagerService 和 Activity 所在的應(yīng)用不在一個(gè)進(jìn)程里绕辖,這里是通過 Binder 通信獲取的一個(gè) WindowManagerService 代理。獲取完 WindowManagerService 代理后通過它來創(chuàng)建出一個(gè)真正要用的 WindowManager 并賦值擂红。即這句代碼:

mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);


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

這里主要就是獲取一個(gè)WindowManagerImpl

attatch主要?jiǎng)?chuàng)建出activity的window綁定windowmanager仪际,從而獲取管理當(dāng)前window的windowmanager,但是并沒有將activity的view添加到window

  • 繼續(xù)看setContentView
public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

查看PhoneWindow源碼setContentView

public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

主要關(guān)注installDecor()

private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this);
        }
       
    }

通過源碼得知篮条,如果當(dāng)前DecorView為空弟头,那么就創(chuàng)建一個(gè),并且跟window進(jìn)行綁定涉茧,DecorView 是 Activity 中的頂級(jí) View赴恨,是一個(gè) FrameLayout。
不過現(xiàn)在仍然沒有將對(duì)應(yīng)的畫面展示到手機(jī)屏幕上

Window 加入到 WindowManager 這一過程要在調(diào)用完 Acitivy 的 onResume() 方法后來實(shí)現(xiàn)伴栓,之后會(huì)調(diào)用 Activity 的 makeVisible():

/**
     * Control whether this activity's main window is visible.  This is intended
     * only for the special case of an activity that is not going to show a
     * UI itself, but can't just finish prior to onResume() because it needs
     * to wait for a service binding or such.  Setting this to false allows
     * you to prevent your UI from being shown during that time.
     *
     * <p>The default value for this is taken from the
     * {@link android.R.attr#windowNoDisplay} attribute of the activity's theme.
     */
    public void setVisible(boolean visible) {
        if (mVisibleFromClient != visible) {
            mVisibleFromClient = visible;
            if (mVisibleFromServer) {
                if (visible) makeVisible();
                else mDecor.setVisibility(View.INVISIBLE);
            }
        }
    }

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

這個(gè)函數(shù)里首先判斷 Window 是否已經(jīng)添加到 WindowManager 中伦连,沒有的話取出在剛剛 attach() 方法中創(chuàng)建的 WindowManager雨饺,將 DecorView 加入進(jìn)去,這里的 DecorView 其實(shí)就是 Window 所持有那個(gè)惑淳。然后再將 DecorView 設(shè)置為顯示狀態(tài)额港,來顯示我們的布局。

  • 至此歧焦,我們需要關(guān)心WindowManager是如何進(jìn)行管理Window
    在實(shí)際使用中無法直接訪問 Window移斩,對(duì) Window 的訪問必須通過 WindowManager。我們已經(jīng)知道 WindowManager 提供的三個(gè)接口方法 addView绢馍、updateViewLayout 以及 removeView 都是針對(duì) View 的向瓷,而這些 View 都被其對(duì)應(yīng)的 Window 所持有,所以上面這些操作實(shí)際上相當(dāng)于對(duì) Window 的操作舰涌,WindowManager 是一個(gè)接口猖任,它的真正實(shí)現(xiàn)由上文可知是 WindowManagerImpl 類。
 public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }

可以知道瓷耙,實(shí)際是交給了mGlobal進(jìn)行處理朱躺,也就是WindowManagerGlobal

  • 繼續(xù)看WindowManagerGlobal源碼的幾個(gè)核心參數(shù)
  //存儲(chǔ)的是所有 Window 所對(duì)應(yīng)的 View
    private final ArrayList<View> mViews = new ArrayList<View>();
   //mRoots 存儲(chǔ)的是所有 Window 所對(duì)應(yīng)的 ViewRootImpl
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
   //mParams 存儲(chǔ)的是所有 Window 所對(duì)應(yīng)的布局參數(shù)
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
//mDyingViews 存儲(chǔ)了那些正在被刪除的 View 對(duì)象,或者說是那些已經(jīng)調(diào)用了 removeView 方法但是操作刪除還未完成的 Window 對(duì)象
    private final ArraySet<View> mDyingViews = new ArraySet<View>();

在 addView () 方法中將這些相關(guān)對(duì)象添加到對(duì)應(yīng)集合中搁痛。最后調(diào)用 root.setView() 方法长搀,setView() 中會(huì)調(diào)用一個(gè)很重要的方法 requestLayout(),其主要是用來刷新頁面落追,其中還有一個(gè)很重要的方法 addToDisplay

framework/base/services/core/java/com/android/server/wm/Session.java

@Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
            Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
            InsetsState outInsetsState) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
             outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
             outInsetsState);
    }

mWindowSession 的類型是 IWindowSession盈滴,它是一個(gè) Binder 對(duì)象,真正的實(shí)現(xiàn)類是 Session轿钠,這也就是之前提到的 IPC 調(diào)用的位置巢钓。也就是說在這里,完成了 WindowManager 和 WindowManagerService 的通信疗垛,將 Window 信息傳給了WindowManagerService症汹。

至此,得出結(jié)論setView() 方法里面會(huì)通過 mWindowSession 這個(gè) Binder 對(duì)象將 Window 傳給 WindowManagerService贷腕。WindowManagerService 來管理各個(gè) Window 的大小和顯示位置背镇,來讓 SurfaceFlinger 渲染。


image.png

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末泽裳,一起剝皮案震驚了整個(gè)濱河市瞒斩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌涮总,老刑警劉巖胸囱,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異瀑梗,居然都是意外死亡烹笔,警方通過查閱死者的電腦和手機(jī)裳扯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谤职,“玉大人饰豺,你說我怎么就攤上這事≡黍冢” “怎么了冤吨?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)陷寝。 經(jīng)常有香客問我锅很,道長(zhǎng)其馏,這世上最難降的妖魔是什么凤跑? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮叛复,結(jié)果婚禮上仔引,老公的妹妹穿的比我還像新娘。我一直安慰自己褐奥,他們只是感情好咖耘,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著撬码,像睡著了一般儿倒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上呜笑,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天夫否,我揣著相機(jī)與錄音,去河邊找鬼叫胁。 笑死凰慈,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的驼鹅。 我是一名探鬼主播微谓,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼输钩!你這毒婦竟也來了豺型?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤买乃,失蹤者是張志新(化名)和其女友劉穎姻氨,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體为牍,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡哼绑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年岩馍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抖韩。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蛀恩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出茂浮,到底是詐尸還是另有隱情双谆,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布席揽,位于F島的核電站顽馋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏幌羞。R本人自食惡果不足惜寸谜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望属桦。 院中可真熱鬧熊痴,春花似錦、人聲如沸聂宾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽系谐。三九已至巾陕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間纪他,已是汗流浹背鄙煤。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留止喷,地道東北人馆类。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像弹谁,于是被迫代替她去往敵國(guó)和親乾巧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容