自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

理性分析 Window、Activity、DecorView 以及 ViewRoot 之間關(guān)系

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

[[433927]]

文末本文轉(zhuǎn)載自微信公眾號「 Android開發(fā)編程」,作者 Android開發(fā)編程。轉(zhuǎn)載本文請聯(lián)系 Android開發(fā)編程公眾號。

前言

Activity和window,DecorView ,viewRoot是什么關(guān)系

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

一、基本概念介紹

1、Activity

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

2、Window

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

3、DecorView

  • DecorView的父類是FrameLayout,是Android View樹的根節(jié);
  • 內(nèi)部包含一個豎直方向的LinearLayout,它有上下三個部分,上面是個ViewStub,延遲加載的視圖(ActionBar,根據(jù)Theme設(shè)置),中間的是標(biāo)題欄(根據(jù)Theme設(shè)置,有的布局沒有),下面的是內(nèi)容欄。setContentView所設(shè)置的布局文件其實就是被加到內(nèi)容欄之中的;
  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樹的一部分。從源碼實現(xiàn)上來看,它既非View的子類,也非View Group,但它實現(xiàn)了ViewParent接口,這讓它可以作為View的名義上的父視圖;
  • RootView繼承了Handler類,可以接收事件并分發(fā);
  • Android的所有觸屏事件、按鍵事件、界面刷新等事件都是通過ViewRoot進行分發(fā)的;

二、DecorView的創(chuàng)建整個流程詳解

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);//創(chuàng)建一個Window對象 
  10.         mWindow.setWindowControllerCallback(this); 
  11.         mWindow.setCallback(this);//設(shè)置回調(diào),向Activity分發(fā)點擊或狀態(tài)改變等事件 
  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設(shè)置WindowManager對象 
  18.         .................................................................... 

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

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

2、setContentView

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

 mContentParent就是ContentView所對應(yīng)的的FrameLayout;

Activity的setContentView的流程大致可以總結(jié)為:

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

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

其中創(chuàng)建的過程中可能根據(jù)Theme不同,加載不同的布局格式,即Activity中設(shè)置的布局;

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設(shè)置布局格式,并返回mContentParent 
  12.         ... 
  13.         }  
  14.     } 
  15. protected DecorView generateDecor() { 
  16.     return new DecorView(getContext(), -1); 

 很簡單,創(chuàng)建了一個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.     // 根據(jù)主題樣式,加載窗口布局 
  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時提到的布局格式,那只是一個例子,根據(jù)主題樣式不同,加載不同的布局。 
  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; 
  •  先從主題中獲取樣式,然后根據(jù)樣式;
  • 加載對應(yīng)的布局到DecorView中,然后從中獲取mContentParent;
  • 獲得到之后,可以回到上面的代碼,為mContentParent添加View,即Activity中的布局;

5、DecorView的顯示

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

  1. private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
  2.     //就是在這里調(diào)用了Activity.attach(),接著調(diào)用了Activity.onCreate()和Activity.onStart()生命周期, 
  3.     //但是由于只是初始化了mDecor,添加了布局文件,還沒有把 
  4.     //mDecor添加到負責(zé)UI顯示的PhoneWindow中,所以這時候?qū)τ脩魜碚f,是不可見的 
  5.     Activity a = performLaunchActivity(r, customIntent); 
  6.     ...... 
  7.     if (a != null) { 
  8.     //這里面執(zhí)行了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.                 //執(zhí)行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()已經(jīng)調(diào)用了,但是現(xiàn)在界面還是不可見的 
  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.                 //在這里,執(zhí)行了重要的操作,使得DecorView可見 
  24.                 if (r.activity.mVisibleFromClient) { 
  25.                     r.activity.makeVisible(); 
  26.                 } 
  27.             } 
  28.         } 
  29.     } 

 當(dāng)我們執(zhí)行了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());
  • 起到了重要的作用,因為其內(nèi)部創(chuàng)建了一個ViewRootImpl對象,負責(zé)繪制顯示各個子View;
  • 具體來看addView()方法,因為WindowManager是個接口,具體是交給WindowManagerImpl來實現(xiàn)的;

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()方法去實現(xiàn); 
  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對象,然后調(diào)用其setView()方法;
  • 其中setView()方法經(jīng)過一些列折騰,最終調(diào)用了performTraversals()方法,完成繪制,最終界面才顯示出來;

總結(jié)

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

 

責(zé)任編輯:武曉燕 來源: Android開發(fā)編程
相關(guān)推薦

2009-04-17 22:25:16

多核四核CPU

2017-02-21 12:20:20

Android事件分發(fā)機制實例解析

2012-10-31 09:20:45

數(shù)據(jù)中心制冷PUE

2016-12-12 09:58:47

AndroidAndroid Vie

2010-03-22 09:43:00

無線交換機

2021-11-04 09:37:31

Android截屏實現(xiàn)方式監(jiān)聽截屏

2013-11-14 17:02:41

Android多窗口

2010-01-11 11:09:10

C++語法

2011-05-19 17:49:08

ActivityAndroid開發(fā)

2024-03-04 11:12:20

大數(shù)據(jù)物聯(lián)網(wǎng)

2021-01-14 12:17:52

大數(shù)據(jù)數(shù)據(jù)分析技術(shù)

2023-03-07 13:28:17

2015-12-09 09:47:50

2009-06-25 14:46:50

JDKJREJVM

2011-08-08 09:51:52

Cocoa 框架

2010-08-03 16:21:54

FlexFlash

2015-03-09 11:01:43

2020-05-12 16:58:05

LinuxUnix技術(shù)

2012-05-31 14:54:59

Hadoop大數(shù)據(jù)

2012-12-27 15:29:33

Android開發(fā)Activity
點贊
收藏

51CTO技術(shù)棧公眾號