成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

理性分析 Window、Activity、DecorView 以及 ViewRoot 之間關系

系統 Windows
ViewRoot并不屬于View樹的一部分。從源碼實現上來看,它既非View的子類,也非View Group,但它實現了ViewParent接口,這讓它可以作為View的名義上的父視圖。

[[433927]]

文末本文轉載自微信公眾號「 Android開發編程」,作者 Android開發編程。轉載本文請聯系 Android開發編程公眾號。

前言

Activity和window,DecorView ,viewRoot是什么關系

今天我們就來講解下,這樣你在面試時候,游刃有余;

一、基本概念介紹

1、Activity

  • Activity負責控制生命周期和處理事件;
  • 負責統籌視圖的添加與顯示,以及通過一些回調方法與Window和View進行交互;
  • 一個Activity包含一個Window,真正控制視圖的是Window,Window才是真正代表一個窗口;
  • 統籌視圖的添加與顯示,通過回調與Window和View進行交互;

2、Window

  • Window是視圖的承載者,是一個抽象類;
  • Activity中持有的實際上是Window的子類PhoneWindow;
  • Window通過WindowManager加載了一個DecorView到Window中,并將DecorView交給了ViewRoot;

3、DecorView

  • DecorView的父類是FrameLayout,是Android View樹的根節;
  • 內部包含一個豎直方向的LinearLayout,它有上下三個部分,上面是個ViewStub,延遲加載的視圖(ActionBar,根據Theme設置),中間的是標題欄(根據Theme設置,有的布局沒有),下面的是內容欄。setContentView所設置的布局文件其實就是被加到內容欄之中的;
  1. ViewGroup content = (ViewGroup)findViewById(android.R.id.content); 
  2. ViewGroup rootView = (ViewGroup) content.getChildAt(0) 

 4、ViewRoot

  • 控制View的事件處理和邏輯處理;
  • ViewRoot子類是ViewRootImpl類,它是連接WindowManagerService和DecorView的紐帶,View的三大流程(測量(measure),布局(layout),繪制(draw))均通過ViewRoot來完成;
  • ViewRoot并不屬于View樹的一部分。從源碼實現上來看,它既非View的子類,也非View Group,但它實現了ViewParent接口,這讓它可以作為View的名義上的父視圖;
  • RootView繼承了Handler類,可以接收事件并分發;
  • Android的所有觸屏事件、按鍵事件、界面刷新等事件都是通過ViewRoot進行分發的;

二、DecorView的創建整個流程詳解

1、attach

Activity的setContentView()開始

  1. public void setContentView(@LayoutRes int layoutResID) { 
  2. getWindow().setContentView(layoutResID); 
  3. initWindowDecorActionBar(); 

 可以看到實際上是交給Window來裝載視圖的;

  1. final void attach(Context context, ActivityThread aThread, 
  2. Instrumentation instr, IBinder token, int ident, 
  3. Application application, Intent intent, ActivityInfo info, 
  4. CharSequence title, Activity parent, String id, 
  5. NonConfigurationInstances lastNonConfigurationInstances, 
  6. Configuration config, String referrer, IVoiceInteractor voiceInteractor, 
  7. Window window) { 
  8. .................................................................. 
  9.         mWindow = new PhoneWindow(this, window);//創建一個Window對象 
  10.         mWindow.setWindowControllerCallback(this); 
  11.         mWindow.setCallback(this);//設置回調,向Activity分發點擊或狀態改變等事件 
  12.         mWindow.setOnWindowDismissedCallback(this); 
  13.         ................................................................. 
  14.         mWindow.setWindowManager( 
  15.         (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), 
  16.         mToken, mComponent.flattenToString(), 
  17.                 (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);//給Window設置WindowManager對象 
  18.         .................................................................... 

 在Activity的attach方法中生成了PhoneWindow的實例;

有了Window對象,接下來就將DecorView加載到Window中;

2、setContentView

  1. public void setContentView(int layoutResID) { 
  2.     if (mContentParent == null) {//mContentParent為空,創建一個DecroView 
  3.     installDecor(); 
  4.     } else { 
  5.         mContentParent.removeAllViews();//mContentParent不為空,刪除其中的View 
  6.     } 
  7.     mLayoutInflater.inflate(layoutResID, mContentParent);//為mContentParent添加子View,即Activity中設置的布局文件 
  8.     final Callback cb = getCallback(); 
  9.     if (cb != null && !isDestroyed()) { 
  10.         cb.onContentChanged();//回調通知,內容改變 
  11.     } 

 mContentParent就是ContentView所對應的的FrameLayout;

Activity的setContentView的流程大致可以總結為:

Activity首先在Attach方法中生成了PhoneWindow的實例;

在setContentView中直接交給Window來裝載視圖,先在PhoneWindow中創建了一個DecroView;

其中創建的過程中可能根據Theme不同,加載不同的布局格式,即Activity中設置的布局;

3、installDecor

  1. private void installDecor() { 
  2.     if (mDecor == null) { 
  3.         mDecor = generateDecor(); //生成DecorView 
  4.         mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); 
  5.         mDecor.setIsRootNamespace(true); 
  6.         if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) { 
  7.             mDecor.postOnAnimation(mInvalidatePanelMenuRunnable); 
  8.         } 
  9.     } 
  10.     if (mContentParent == null) { 
  11.         mContentParent = generateLayout(mDecor); // 為DecorView設置布局格式,并返回mContentParent 
  12.         ... 
  13.         }  
  14.     } 
  15. protected DecorView generateDecor() { 
  16.     return new DecorView(getContext(), -1); 

 很簡單,創建了一個DecorView;

再看generateLayout;

4、generateLayout

  1. protected ViewGroup generateLayout(DecorView decor) { 
  2.     // 從主題文件中獲取樣式信息 
  3.     TypedArray a = getWindowStyle(); 
  4.     ................... 
  5.     if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) { 
  6.         requestFeature(FEATURE_NO_TITLE); 
  7.     } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) { 
  8.         // Don't allow an action bar if there is no title. 
  9.         requestFeature(FEATURE_ACTION_BAR); 
  10.     } 
  11.     ................ 
  12.     // 根據主題樣式,加載窗口布局 
  13.     int layoutResource; 
  14.     int features = getLocalFeatures(); 
  15.     // System.out.println("Features: 0x" + Integer.toHexString(features)); 
  16.     if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) { 
  17.         layoutResource = R.layout.screen_swipe_dismiss; 
  18.     } else if(...){ 
  19.         ... 
  20.     } 
  21.     View in = mLayoutInflater.inflate(layoutResource, null);//加載layoutResource 
  22.     //往DecorView中添加子View,即文章開頭介紹DecorView時提到的布局格式,那只是一個例子,根據主題樣式不同,加載不同的布局。 
  23.     decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));  
  24.     mContentRoot = (ViewGroup) in
  25.     ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);// 這里獲取的就是mContentParent 
  26.     if (contentParent == null) { 
  27.         throw new RuntimeException("Window couldn't find content container view"); 
  28.     } 
  29.     if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { 
  30.         ProgressBar progress = getCircularProgressBar(false); 
  31.         if (progress != null) { 
  32.             progress.setIndeterminate(true); 
  33.         } 
  34.     } 
  35.     if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) { 
  36.         registerSwipeCallbacks(); 
  37.     } 
  38.     // Remaining setup -- of background and title -- that only applies 
  39.     // to top-level windows. 
  40.     ... 
  41.     return contentParent; 
  •  先從主題中獲取樣式,然后根據樣式;
  • 加載對應的布局到DecorView中,然后從中獲取mContentParent;
  • 獲得到之后,可以回到上面的代碼,為mContentParent添加View,即Activity中的布局;

5、DecorView的顯示

將DecorView建立起來,通過setContentView設置的界面,如何在onResume后對用戶可見,需要從ActivityThread說起;

  1. private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
  2.     //就是在這里調用了Activity.attach(),接著調用了Activity.onCreate()和Activity.onStart()生命周期, 
  3.     //但是由于只是初始化了mDecor,添加了布局文件,還沒有把 
  4.     //mDecor添加到負責UI顯示的PhoneWindow中,所以這時候對用戶來說,是不可見的 
  5.     Activity a = performLaunchActivity(r, customIntent); 
  6.     ...... 
  7.     if (a != null) { 
  8.     //這里面執行了Activity.onResume() 
  9.     handleResumeActivity(r.token, false, r.isForward, 
  10.                         !r.activity.mFinished && !r.startsNotResumed); 
  11.     if (!r.activity.mFinished && r.startsNotResumed) { 
  12.         try { 
  13.                 r.activity.mCalled = false
  14.                 //執行Activity.onPause() 
  15.                 mInstrumentation.callActivityOnPause(r.activity); 
  16.                 } 
  17.         } 
  18.     } 

 重點看下handleResumeActivity(),在這其中,DecorView將會顯示出來,同時重要的一個角色;ViewRoot也將登場;

6、handleResumeActivity

  1. final void handleResumeActivity(IBinder token, boolean clearHide,  
  2.                                 boolean isForward, boolean reallyResume) { 
  3.     //這個時候,Activity.onResume()已經調用了,但是現在界面還是不可見的 
  4.     ActivityClientRecord r = performResumeActivity(token, clearHide); 
  5.     if (r != null) { 
  6.         final Activity a = r.activity; 
  7.         if (r.window == null && !a.mFinished && willBeVisible) { 
  8.             r.window = r.activity.getWindow(); 
  9.             View decor = r.window.getDecorView(); 
  10.             //decor對用戶不可見 
  11.             decor.setVisibility(View.INVISIBLE); 
  12.             ViewManager wm = a.getWindowManager(); 
  13.             WindowManager.LayoutParams l = r.window.getAttributes(); 
  14.             a.mDecor = decor; 
  15.             l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 
  16.             if (a.mVisibleFromClient) { 
  17.                 a.mWindowAdded = true
  18.                 //被添加進WindowManager了,但是這個時候,還是不可見的 
  19.                 wm.addView(decor, l); 
  20.             } 
  21.             if (!r.activity.mFinished && willBeVisible 
  22.                     && r.activity.mDecor != null && !r.hideForNow) { 
  23.                 //在這里,執行了重要的操作,使得DecorView可見 
  24.                 if (r.activity.mVisibleFromClient) { 
  25.                     r.activity.makeVisible(); 
  26.                 } 
  27.             } 
  28.         } 
  29.     } 

 當我們執行了Activity.makeVisible()方法之后,界面才對我們是可見的;

  1. void makeVisible() { 
  2.    if (!mWindowAdded) { 
  3.         ViewManager wm = getWindowManager(); 
  4.         wm.addView(mDecor, getWindow().getAttributes());//將DecorView添加到WindowManager 
  5.         mWindowAdded = true
  6.     } 
  7.     mDecor.setVisibility(View.VISIBLE);//DecorView可見 
  •  到此DecorView便可見,顯示在屏幕中;
  • 但是在這其中,wm.addView(mDecor, getWindow().getAttributes());
  • 起到了重要的作用,因為其內部創建了一個ViewRootImpl對象,負責繪制顯示各個子View;
  • 具體來看addView()方法,因為WindowManager是個接口,具體是交給WindowManagerImpl來實現的;

7、addView

  1. public final class WindowManagerImpl implements WindowManager {     
  2.     private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); 
  3.     ... 
  4.     @Override 
  5.     public void addView(View view, ViewGroup.LayoutParams params) { 
  6.         mGlobal.addView(view, params, mDisplay, mParentWindow); 
  7.     } 
  8. 交給WindowManagerGlobal 的addView()方法去實現; 
  9. public void addView(View view, ViewGroup.LayoutParams params, 
  10.                     Display display, Window parentWindow) { 
  11.     final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; 
  12.     ...... 
  13.     synchronized (mLock) { 
  14.         ViewRootImpl root; 
  15.         //實例化一個ViewRootImpl對象 
  16.         root = new ViewRootImpl(view.getContext(), display); 
  17.         view.setLayoutParams(wparams); 
  18.         mViews.add(view); 
  19.         mRoots.add(root); 
  20.         mParams.add(wparams); 
  21.     } 
  22.     ...... 
  23.     try { 
  24.         //將DecorView交給ViewRootImpl 
  25.         root.setView(view, wparams, panelParentView); 
  26.     } catch (RuntimeException e) { 
  27.     } 
  •  看到其中實例化了ViewRootImpl對象,然后調用其setView()方法;
  • 其中setView()方法經過一些列折騰,最終調用了performTraversals()方法,完成繪制,最終界面才顯示出來;

總結

  • Activity就像個控制器,不負責視圖部分。Window像個承載器,裝著內部視圖;
  • DecorView就是個頂層視圖,是所有View的最外層布局;
  • ViewRoot像個連接器,負責溝通,通過硬件的感知來通知視圖,進行用戶之間的交互;

 

責任編輯:武曉燕 來源: Android開發編程
相關推薦

2009-04-17 22:25:16

多核四核CPU

2017-02-21 12:20:20

Android事件分發機制實例解析

2012-10-31 09:20:45

數據中心制冷PUE

2016-12-12 09:58:47

AndroidAndroid Vie

2021-11-04 09:37:31

Android截屏實現方式監聽截屏

2013-11-14 17:02:41

Android多窗口

2010-03-22 09:43:00

無線交換機

2010-01-11 11:09:10

C++語法

2011-05-19 17:49:08

ActivityAndroid開發

2024-03-04 11:12:20

大數據物聯網

2023-03-07 13:28:17

2021-01-14 12:17:52

大數據數據分析技術

2015-12-09 09:47:50

2009-06-25 14:46:50

JDKJREJVM

2012-05-31 14:54:59

Hadoop大數據

2011-08-08 09:51:52

Cocoa 框架

2015-03-09 11:01:43

2010-08-03 16:21:54

FlexFlash

2020-05-12 16:58:05

LinuxUnix技術

2012-08-06 10:17:24

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩一区二区三区在线看 | 午夜国产羞羞视频免费网站 | 久久久久久久久久久爱 | 国产乱码久久久 | 欧美视频一区 | 亚洲国产精品va在线看黑人 | 91精品国产一区二区三区 | 日韩欧美在线播放 | 久久久精品视频免费 | 免费一区 | 精品欧美一区二区三区久久久 | 羞羞的视频免费在线观看 | 亚洲一区二区在线 | 亚洲精品黄色 | a在线免费观看视频 | 一级看片免费视频囗交动图 | 免费观看日韩av | 综合一区二区三区 | 99在线免费观看视频 | 一区二区三区亚洲视频 | 久久久久久久久久久久91 | 久久久久国产精品一区二区 | 天天干人人 | 99re视频在线 | 亚洲字幕在线观看 | 在线观看久草 | 亚洲国产aⅴ精品一区二区 免费观看av | 一区二区三区在线播放 | 欧美成人在线免费 | 欧洲一级视频 | 激情久久av一区av二区av三区 | 欧洲一级毛片 | 久久久www成人免费精品 | 翔田千里一区二区 | 国产日韩欧美精品 | 欧美精品一二三区 | 欧美黄 片免费观看 | 天天躁人人躁人人躁狂躁 | 国产一级片免费在线观看 | 国产一级片91 | 91麻豆产精品久久久久久夏晴子 |