Android系統(tǒng)_Window的創(chuàng)建和添加流程分析

流程圖

(大體流程矛市,從Activity接受啟動開始)

源碼分析

基于API 23

Window創(chuàng)建

ActivityThread.handleLaunchActivity
ActivityThread.performLaunchActivity

ActivityThread處理并執(zhí)行Activity啟動

//ActivityThread
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    //獲取WindowManagerService的Binder引用(proxy端)拗秘。
    WindowManagerGlobal.initialize();

    //執(zhí)行Activity的onCreate,onStart,onResotreInstanceState方法
    Activity a = performLaunchActivity(r, customIntent);
    if (a != null) {
        ...
        //執(zhí)行Activity的onResume方法.
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

        ...
    } 

}


private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

   //通過類加載器創(chuàng)建Activity
   Activity activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);

   ...      

   //通過LoadedApk的makeApplication方法來創(chuàng)建Application對象
   Application app = r.packageInfo.makeApplication(false, mInstrumentation);


   if (activity != null) {
       ...
       // 執(zhí)行 attach 方法
       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);
       ...

       //onCreate
       mInstrumentation.callActivityOnCreate(activity, r.state);

       //onStart
       activity.performStart();

   }
   return activity;
}

Activity.attach
  • 構(gòu)造PhoneWindow (Window唯一具體實現(xiàn))
  • 設(shè)置自身為Window的Callback秒紧,從而Activity能作為callback接受window的key和touch事件
  • 初始化且設(shè)置WindowManager交排,每個Activity對應(yīng)一個WindowManager盛撑,通過WM與WMS進行通信
final void attach(...) {
    //綁定上下文
    attachBaseContext(context);
    
    //創(chuàng)建Window,PhoneWindow是Window的唯一具體實現(xiàn)類
    mWindow = new PhoneWindow(this, window);//此處的window==null植阴,但不影響
    mWindow.setWindowControllerCallback(this);
    // 設(shè)置 Window.Callback
    mWindow.setCallback(this);
    ...
    //設(shè)置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();//其實它是WindowManagerImpl

}

Window添加View過程

前面在handleLauncherActivity完成了PhoneWindow的創(chuàng)建過程涧卵,下面我們繼續(xù)查看Activity執(zhí)行生命周期handleResumeActivity方法勤家,查看Activity對應(yīng)View被加載到PhoneWindow容器過程

ActivityThread.handleResumeActivity
  • 獲取ActivityClientRecord,將對應(yīng)DecorView設(shè)置為不可見柳恐,因為當(dāng)前View還未繪制
  • 通過Window對應(yīng)的WindowManager執(zhí)行addView(decor伐脖,l)操作
  • View繪制完成后,會將decorView設(shè)置可見乐设,展示該Activity對應(yīng)內(nèi)容讼庇,最后onResume完成
final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {

   //把activity數(shù)據(jù)記錄更新到ActivityClientRecord
   ActivityClientRecord r = performResumeActivity(token, clearHide);

   if (r != null) {

       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;

           ...
           if (a.mVisibleFromClient && !a.mWindowAdded) {
               a.mWindowAdded = true;
               wm.addView(decor, l);// 把decor添加到窗口上
           }

       } 
           //屏幕參數(shù)發(fā)生了改變
           performConfigurationChanged(r.activity, r.tmpConfig);

           WindowManager.LayoutParams l = r.window.getAttributes();

               if (r.activity.mVisibleFromClient) {
                   ViewManager wm = a.getWindowManager();
                   View decor = r.window.getDecorView();
                   wm.updateViewLayout(decor, l);//更新窗口狀態(tài)
               }


           ...
           if (r.activity.mVisibleFromClient) {
               //已經(jīng)成功添加到窗口上了(繪制和事件接收),設(shè)置為可見
               r.activity.makeVisible();
           }


       //通知ActivityManagerService伤提,Activity完成Resumed
        ActivityManagerNative.getDefault().activityResumed(token);
   } 

}

WindowManagerImply.addView
WindowManagerGlobal.addView
  • WindowManagerImpl的全局變量通過單例模式初始化了WindowManagerGlobal巫俺,(一個進程一個WMG對象)
  • Window管理類添加View過程,創(chuàng)建ViewRootImpl肿男,將View處理操作交給ViewRootImpl實現(xiàn)
// WindowManagerImply
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mDisplay, mParentWindow);
}

// WindowManagerGlobal
public void addView(View view, ViewGroup.LayoutParams params,
           Display display, Window parentWindow) {
     
    synchronized (mLock) { 
        ...
        // 創(chuàng)建ViewRootImpl介汹,并將View與之綁定
        root = new ViewRootImpl(view.getContext(), display);
        
        view.setLayoutParams(wparams);
        
        mViews.add(view); // 將當(dāng)前view添加到mView集合中
        mRoots.add(root); // 將當(dāng)前root添加mRoots集合中
        mParams.add(wparams); // 將當(dāng)前window的params添加到mParams集合中
    }
    
    // setView 完成View的繪制流程却嗡,并添加到window上 
    root.setView(view, wparams, panelParentView);
   
}

ViewRootImpl.setView

  • ViewRootImpl構(gòu)建過程中,會通過WindowManagerGlobal的getWindowSession(static方法)獲取IWindowSession即WindowSession
  • 執(zhí)行requestLayout方法完成View的繪制流程
  • 通過WindowSession與WindowManagerService通信嘹承,將View和InputChannel添加到WMS窗价,從而展示View并可以接受輸入事件

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {

      ...
      int res
      requestLayout();//執(zhí)行 View的繪制流程

      if ((mWindowAttributes.inputFeatures
              & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
          // 創(chuàng)建InputChannel
          mInputChannel = new InputChannel();
      }

      try {

          //通過WindowSession進行IPC調(diào)用,將View添加到Window上
          //mWindow即W類叹卷,用來接收WmS信息
          //同時通過InputChannel接收觸摸事件回調(diào)
          res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                  getHostVisibility(), mDisplay.getDisplayId(),
                  mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                  mAttachInfo.mOutsets, mInputChannel);
      }

      ...

      //處理觸摸事件回調(diào)
      mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                  Looper.myLooper());

}

WindowSession.addToDisplay

  • Session執(zhí)行addToDisplay方法撼港,通過調(diào)用成員變量WMS進行addWindow操作
public int addToDisplay(...) {
   return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
           outContentInsets, outStableInsets, outOutsets, outInputChannel);

}

WindowManagerService.addWindow

  • 創(chuàng)建WindowState,保存Window狀態(tài)
  • 調(diào)整LayoutParams參數(shù)骤竹、設(shè)置input帝牡、設(shè)置window zOrder
  • 執(zhí)行WindowState的attach(創(chuàng)建Surface過程,詳情見下一篇)
public int addWindow(Session session, IWindow client, int seq,
       WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
       Rect outContentInsets, Rect outStableInsets, Rect outOutsets,InputChannel outInputChannel) {
   
    ... // 一堆check邏輯

    WindowToken token = mTokenMap.get(attrs.token);
    //創(chuàng)建 WindowState
    WindowState win = new WindowState(this, session, client, token,
          attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
    ...

    //調(diào)整 WindowManager 的 LayoutParams 參數(shù)
    mPolicy.adjustWindowParamsLw(win.mAttrs);
    res = mPolicy.prepareAddWindowLw(win, attrs);
    addWindowToListInOrderLocked(win, true);

    // 設(shè)置 input
    mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);

    // 創(chuàng)建 Surface 與 SurfaceFlinger 通信蒙揣,
    win.attach();
    mWindowMap.put(client.asBinder(), win);
        
    if (win.canReceiveKeys()) {
    //當(dāng)該窗口能接收按鍵事件靶溜,則更新聚焦窗口
    focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
          false /*updateInputWindows*/);
    }
    assignLayersLocked(displayContent.getWindowList());

    ...

}


推薦閱讀:圖形系統(tǒng)總結(jié)
參考
Android Window 機制探索

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市懒震,隨后出現(xiàn)的幾起案子罩息,更是在濱河造成了極大的恐慌,老刑警劉巖个扰,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓷炮,死亡現(xiàn)場離奇詭異,居然都是意外死亡递宅,警方通過查閱死者的電腦和手機娘香,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來办龄,“玉大人茅主,你說我怎么就攤上這事⊥亮瘢” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵响牛,是天一觀的道長玷禽。 經(jīng)常有香客問我,道長呀打,這世上最難降的妖魔是什么矢赁? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮贬丛,結(jié)果婚禮上撩银,老公的妹妹穿的比我還像新娘。我一直安慰自己豺憔,他們只是感情好额获,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布够庙。 她就那樣靜靜地躺著,像睡著了一般抄邀。 火紅的嫁衣襯著肌膚如雪耘眨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天境肾,我揣著相機與錄音剔难,去河邊找鬼。 笑死奥喻,一個胖子當(dāng)著我的面吹牛偶宫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播环鲤,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼纯趋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了楔绞?” 一聲冷哼從身側(cè)響起结闸,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎酒朵,沒想到半個月后桦锄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡蔫耽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年结耀,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匙铡。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡图甜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鳖眼,到底是詐尸還是另有隱情黑毅,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布钦讳,位于F島的核電站矿瘦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏愿卒。R本人自食惡果不足惜缚去,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琼开。 院中可真熱鬧易结,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至滋尉,卻和暖如春玉控,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背狮惜。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工高诺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人碾篡。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓虱而,卻偏偏與公主長得像,于是被迫代替她去往敵國和親开泽。 傳聞我的和親對象是個殘疾皇子牡拇,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

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