乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Android中將布局文件/View添加至窗口過(guò)程分析

       muyable 2014-05-04

                                   

                                                                                                          轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/qinjuning     

       

       

       

               本文主要內(nèi)容是講解一個(gè)視圖View或者一個(gè)ViewGroup對(duì)象是如何添加至應(yīng)用程序窗口中的。

       

              下文中提到的窗口可泛指能看到的界面,包括一個(gè)Activity呈現(xiàn)的界面(我們可以將之理解為應(yīng)用程序窗口),一個(gè)Dialog,

         一個(gè)Toast,一個(gè)Menu菜單等。

            首先對(duì)相關(guān)類的作用進(jìn)行一下簡(jiǎn)單介紹:

       

               Window 類   位于 /frameworks/base/core/java/android/view/Window.java

                  說(shuō)明:該類是一個(gè)抽象類,提供了繪制窗口的一組通用API??梢詫⒅斫鉃橐粋€(gè)載體,各種View在這個(gè)載體上顯示。

                   源文件(部分)如下:

      1. public abstract class Window {    
      2.     //...  
      3.     //指定Activity窗口的風(fēng)格類型  
      4.     public static final int FEATURE_NO_TITLE = 1;  
      5.     public static final int FEATURE_INDETERMINATE_PROGRESS = 5;  
      6.       
      7.     //設(shè)置布局文件  
      8.     public abstract void setContentView(int layoutResID);  
      9.   
      10.     public abstract void setContentView(View view);  
      11.   
      12.     //請(qǐng)求指定Activity窗口的風(fēng)格類型  
      13.     public boolean requestFeature(int featureId) {  
      14.         final int flag = 1<<featureId;  
      15.         mFeatures |= flag;  
      16.         mLocalFeatures |= mContainer != null ? (flag&~mContainer.mFeatures) : flag;  
      17.         return (mFeatures&flag) != 0;  
      18.     }      
      19.     //...  
      20. }  

             PhoneWindow類  位于/frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindow.java

               說(shuō)明: 該類繼承于Window類,是Window類的具體實(shí)現(xiàn),即我們可以通過(guò)該類具體去繪制窗口。并且,該類內(nèi)部包含了

                  一個(gè)DecorView對(duì)象,該DectorView對(duì)象是所有應(yīng)用窗口(Activity界面)的根View。 簡(jiǎn)而言之,PhoneWindow類是

                  把一個(gè)FrameLayout類即DecorView對(duì)象進(jìn)行一定的包裝,將它作為應(yīng)用窗口的根View,并提供一組通用的窗口操作

                  接口。

                     源文件(部分)如下:          

      1. public class PhoneWindow extends Window implements MenuBuilder.Callback {  
      2.     //...  
      3.     // This is the top-level view of the window, containing the window decor.  
      4.     private DecorView mDecor;  //該對(duì)象是所有應(yīng)用窗口的根視圖 , 是FrameLayout的子類  
      5.       
      6.     //該對(duì)象是Activity布局文件的父視圖,一般來(lái)說(shuō)是一個(gè)FrameLayout型的ViewGroup   
      7.     // 同時(shí)也是DecorView對(duì)象的一個(gè)子視圖  
      8.     // This is the view in which the window contents are placed. It is either  
      9.     // mDecor itself, or a child of mDecor where the contents go.  
      10.     private ViewGroup mContentParent;   
      11.       
      12.     //設(shè)置標(biāo)題  
      13.     @Override  
      14.     public void setTitle(CharSequence title) {  
      15.         if (mTitleView != null) {  
      16.             mTitleView.setText(title);  
      17.         }  
      18.         mTitle = title;  
      19.     }  
      20.     //設(shè)置背景圖片  
      21.     @Override  
      22.     public final void setBackgroundDrawable(Drawable drawable) {  
      23.         if (drawable != mBackgroundDrawable || mBackgroundResource != 0) {  
      24.             mBackgroundResource = 0;  
      25.             mBackgroundDrawable = drawable;  
      26.             if (mDecor != null) {  
      27.                 mDecor.setWindowBackground(drawable);  
      28.             }  
      29.         }  
      30.     }  
      31.     //...      
      32. }  

             DecorView類    該類是PhoneWindow類的內(nèi)部類

               說(shuō)明: 該類是一個(gè)FrameLayout的子類,并且是PhoneWindow的子類,該類就是對(duì)普通的FrameLayout進(jìn)行功能的擴(kuò)展,

                  更確切點(diǎn)可以說(shuō)是修飾(Decor的英文全稱是Decoration,即“修飾”的意思),比如說(shuō)添加TitleBar(標(biāo)題欄),以及

                  TitleBar上的滾動(dòng)條等 。最重要的一點(diǎn)是,它是所有應(yīng)用窗口的根View 。

               如下所示 :

         

                     

                 DecorView 根視圖結(jié)構(gòu)                                                          DecorView 根視圖形式

           

           源文件(部分)如下:

      1. private final class DecorView extends FrameLayout {  
      2.     //...  
      3.     //觸摸事件處理  
      4.     @Override  
      5.     public boolean onTouchEvent(MotionEvent event) {  
      6.         return onInterceptTouchEvent(event);  
      7.     }  
      8.     //...  
      9. }  


       

             打個(gè)不恰當(dāng)比喻吧,Window類相當(dāng)于一幅畫(huà)(抽象概念,什么畫(huà)我們未知) ,PhoneWindow為一副齊白石先生的山水畫(huà)

         (具體概念,我們知道了是誰(shuí)的、什么性質(zhì)的畫(huà)),DecorView則為該山水畫(huà)的具體內(nèi)容(有山、有水、有樹(shù),各種界面)。

         DecorView呈現(xiàn)在PhoneWindow上。

       

       

       

             當(dāng)系統(tǒng)(一般是ActivityManagerService)配置好啟動(dòng)一個(gè)Activity的相關(guān)參數(shù)(包括Activity對(duì)象和Window對(duì)象信息)后,

         就會(huì)回調(diào)Activity的onCreate()方法,在其中我們通過(guò)設(shè)置setContentView()方法類設(shè)置該Activity的顯示界面,整個(gè)調(diào)用鏈

         由此鋪墊開(kāi)來(lái)。setContentView()的三個(gè)構(gòu)造方法調(diào)用流程本質(zhì)上是一樣的,我們就分析setContentView(intresId)方法。

        

          

                 

      Step 1  、Activity.setContentView(intresId)   該方法在Activity類中

               該方法只是簡(jiǎn)單的回調(diào)Window對(duì)象,具體為PhoneWindow對(duì)象的setContentView()方法實(shí)現(xiàn) 。

      1. public void setContentView(int layoutResID) {  
      2.     getWindow().setContentView(layoutResID);  
      3. }  
      4.   
      5. public Window getWindow() {  
      6.     return mWindow;   //Window對(duì)象,本質(zhì)上是一個(gè)PhoneWindow對(duì)象  
      7. }  

       Step 2  、PhoneWindow.setContentView()     該方法在PhoneWindow類中 

       

      1. @Override  
      2. public void setContentView(int layoutResID) {  
      3.     //是否是第一次調(diào)用setContentView方法, 如果是第一次調(diào)用,則mDecor和mContentParent對(duì)象都為空  
      4.     if (mContentParent == null) {  
      5.         installDecor();  
      6.     } else {  
      7.         mContentParent.removeAllViews();  
      8.     }  
      9.     mLayoutInflater.inflate(layoutResID, mContentParent);  
      10.     final Callback cb = getCallback();  
      11.     if (cb != null) {  
      12.         cb.onContentChanged();  
      13.     }  
      14. }  


             該方法根據(jù)首先判斷是否已經(jīng)由setContentView()了獲取mContentParent即View對(duì)象, 即是否是第一次調(diào)用該

         PhoneWindow對(duì)象setContentView()方法。如果是第一次調(diào)用,則調(diào)用installDecor()方法,否則,移除該mContentParent內(nèi)

         所有的所有子View。最后將我們的資源文件通過(guò)LayoutInflater對(duì)象轉(zhuǎn)換為View樹(shù),并且添加至mContentParent視圖中。

            

             PS:因此,在應(yīng)用程序里,我們可以多次調(diào)用setContentView()來(lái)顯示我們的界面。


       Step 3、 PhoneWindow. installDecor()    該方法在PhoneWindow類中


      1. private void installDecor() {  
      2.     if (mDecor == null) {  
      3.         //mDecor為空,則創(chuàng)建一個(gè)Decor對(duì)象  
      4.         mDecor = generateDecor();  
      5.         mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);  
      6.         mDecor.setIsRootNamespace(true);  
      7.     }  
      8.     if (mContentParent == null) {  
      9.         //generateLayout()方法會(huì)根據(jù)窗口的風(fēng)格修飾,選擇對(duì)應(yīng)的修飾布局文件  
      10.         //并且將id為content(android:id="@+id/content")的FrameLayout賦值給mContentParent  
      11.         mContentParent = generateLayout(mDecor);  
      12.           
      13.         //...  
      14. }  

         首先、該方法首先判斷mDecor對(duì)象是否為空,如果不為空,則調(diào)用generateDecor()創(chuàng)建一個(gè)DecorView(該類是

                 FrameLayout子類,即一個(gè)ViewGroup視圖) ;


            generateDecor()方法原型為:

      1. protected DecorView generateDecor() {  
      2.     return new DecorView(getContext(), -1);  
      3. }  

        其次、繼續(xù)判斷mContentParent對(duì)象是否為空,如果不為空,則調(diào)用generateLayout()方法去創(chuàng)建mContentParent對(duì)象。

               generateLayout()方法如下:

      1. protected ViewGroup generateLayout(DecorView decor) {  
      2.     // Apply data from current theme.  
      3.   
      4.     //...1、根據(jù)requestFreature()和Activity節(jié)點(diǎn)的android:theme="" 設(shè)置好 features值  
      5.       
      6.     //2 根據(jù)設(shè)定好的 features值,即特定風(fēng)格屬性,選擇不同的窗口修飾布局文件  
      7.     int layoutResource;  //窗口修飾布局文件    
      8.     int features = getLocalFeatures();  
      9.     // System.out.println("Features: 0x" + Integer.toHexString(features));  
      10.     if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {  
      11.         if (mIsFloating) {  
      12.             layoutResource = com.android.internal.R.layout.dialog_title_icons;  
      13.         } else {  
      14.             layoutResource = com.android.internal.R.layout.screen_title_icons;  
      15.         }  
      16.         // System.out.println("Title Icons!");  
      17.     } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {  
      18.         // Special case for a window with only a progress bar (and title).  
      19.         // XXX Need to have a no-title version of embedded windows.  
      20.         layoutResource = com.android.internal.R.layout.screen_progress;  
      21.         // System.out.println("Progress!");  
      22.     }   
      23.     //...  
      24.       
      25.     //3 選定了窗口修飾布局文件 ,添加至DecorView對(duì)象里,并且指定mcontentParent值  
      26.     View in = mLayoutInflater.inflate(layoutResource, null);  
      27.     decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));  
      28.   
      29.     ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);  
      30.     if (contentParent == null) {  
      31.         throw new RuntimeException("Window couldn't find content container view");  
      32.     }  
      33.   
      34.     if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {  
      35.         ProgressBar progress = getCircularProgressBar(false);  
      36.         if (progress != null) {  
      37.             progress.setIndeterminate(true);  
      38.         }  
      39.     }  
      40.     //...  
      41.     return contentParent;  
      42. }  



       該方法會(huì)做如下事情:

         1、根據(jù)窗口的風(fēng)格修飾類型為該窗口選擇不同的窗口布局文件(根視圖)。這些窗口修飾布局文件指定一個(gè)用來(lái)存放

               Activity自定義布局文件的ViewGroup視圖,一般為FrameLayout 其id 為: android:id="@android:id/content"。

              例如窗口修飾類型包括FullScreen(全屏)、NoTitleBar(不含標(biāo)題欄)等。選定窗口修飾類型有兩種:

                 ①、指定requestFeature()指定窗口修飾符,PhoneWindow對(duì)象調(diào)用getLocalFeature()方法獲取值;

                 ②、為我們的Activity配置相應(yīng)屬性,即android:theme=“”,PhoneWindow對(duì)象調(diào)用getWindowStyle()方法

                    獲取值。

              舉例如下,隱藏標(biāo)題欄有如下方法:requestWindowFeature(Window.FEATURE_NO_TITLE);

                         或者 為Activity配置xml屬性:android:theme=”@android:style/Theme.NoTitleBar”。

       

              PS:因此,在Activity中必須在setContentView之前調(diào)用requestFeature()方法。


        確定好窗口風(fēng)格之后,選定該風(fēng)格對(duì)應(yīng)的布局文件,這些布局文件位于 frameworks/base/core/res/layout/  ,

              典型的窗口布局文件有:

                R.layout.dialog_titile_icons                          R.layout.screen_title_icons

                R.layout.screen_progress                             R.layout.dialog_custom_title

                R.layout.dialog_title   

                R.layout.screen_title         // 最常用的Activity窗口修飾布局文件

                R.layout.screen_simple    //全屏的Activity窗口布局文件



         分析Activity最常用的一種窗口布局文件,R.layout.screen_title  :


      1. <!--  
      2. This is an optimized layout for a screen, with the minimum set of features  
      3. enabled.  
      4. -->  
      5.   
      6. <LinearLayout xmlns:android="http://schemas./apk/res/android"  
      7.     android:orientation="vertical"  
      8.     android:fitsSystemWindows="true">  
      9.     <FrameLayout  
      10.         android:layout_width="match_parent"   
      11.         android:layout_height="?android:attr/windowTitleSize"  
      12.         style="?android:attr/windowTitleBackgroundStyle">  
      13.         <TextView android:id="@android:id/title"   
      14.             style="?android:attr/windowTitleStyle"  
      15.             android:background="@null"  
      16.             android:fadingEdge="horizontal"  
      17.             android:gravity="center_vertical"  
      18.             android:layout_width="match_parent"  
      19.             android:layout_height="match_parent" />  
      20.     </FrameLayout>  
      21.     <FrameLayout android:id="@android:id/content"  
      22.         android:layout_width="match_parent"   
      23.         android:layout_height="0dip"  
      24.         android:layout_weight="1"  
      25.         android:foregroundGravity="fill_horizontal|top"  
      26.         android:foreground="?android:attr/windowContentOverlay" />  
      27. </LinearLayout>  

             該布局文件很簡(jiǎn)單,一個(gè)LinearLayout下包含了兩個(gè)子FrameLayout視圖,第一個(gè)FrameLayout用來(lái)顯示標(biāo)題欄(TitleBar),

        該TextView 視圖id為title(android:id="@android:id/title");第二個(gè)FrameLayout用來(lái)顯示我們Activity的布局文件的父視圖,

        該FrameLayoutid為content(android:id="@android:id/content") 。

       

        全屏的窗口布局文件 R.layout.screen_simple:


      1. <--This is an optimized layout for a screen, with the minimum set of features  
      2. enabled.  
      3. -->  
      4.   
      5. <FrameLayout xmlns:android="http://schemas./apk/res/android"  
      6.     android:id="@android:id/content"  
      7.     android:fitsSystemWindows="true"  
      8.     android:foregroundInsidePadding="false"  
      9.     android:foregroundGravity="fill_horizontal|top"  
      10.     android:foreground="?android:attr/windowContentOverlay" />  

           

                  該布局文件只有一個(gè)FrameLayout,用來(lái)顯示我們Activity的布局文件,該FrameLayoutid

          android:id="@android:id/content"


        2、前面一步我們確定窗口修飾布局文件后,mDecor做為根視圖將該窗口布局對(duì)應(yīng)的視圖添加進(jìn)去,并且獲取id為content

                的View,將其賦值給mContentParent對(duì)象,即我們前面中提到的第二個(gè)FrameLayout。

       

         At Last、產(chǎn)生了mDecor和mContentParent對(duì)象后,就將我們的Activity布局文件直接添加至mContentParent父視圖中即可。

            我們?cè)俅?/span>回到 Step 2 中PhoneWindow.setContentView()      該方法在PhoneWindow類中


      1. @Override  
      2. public void setContentView(int layoutResID) {  
      3.     if (mContentParent == null) {  
      4.         installDecor();  
      5.     } else {  
      6.         mContentParent.removeAllViews();  
      7.     }  
      8.     mLayoutInflater.inflate(layoutResID, mContentParent);  
      9.     final Callback cb = getCallback();  
      10.     if (cb != null) {  
      11.         cb.onContentChanged();  
      12.     }  
      13. }  


        整個(gè)過(guò)程主要是如何把Activity的布局文件添加至窗口里,上面的過(guò)程可以概括為:

                    1、創(chuàng)建一個(gè)DecorView對(duì)象,該對(duì)象將作為整個(gè)應(yīng)用窗口的根視圖

                    2、創(chuàng)建不同的窗口修飾布局文件,并且獲取Activity的布局文件該存放的地方,由該窗口修飾布局文件內(nèi)id為content的

                        FrameLayout指定 。

                    3、將Activity的布局文件添加至id為content的FrameLayout內(nèi)。

             最后,當(dāng)AMS(ActivityManagerService)準(zhǔn)備resume一個(gè)Activity時(shí),會(huì)回調(diào)該Activity的handleResumeActivity()方法,

        該方法會(huì)調(diào)用Activity的makeVisible方法 ,顯示我們剛才創(chuàng)建的mDecor 視圖族。

         

      1. //系統(tǒng)resume一個(gè)Activity時(shí),調(diào)用此方法  
      2. final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {  
      3.     ActivityRecord r = performResumeActivity(token, clearHide);  
      4.     //...  
      5.      if (r.activity.mVisibleFromClient) {  
      6.          r.activity.makeVisible();  
      7.      }  
      8. }  

          handleResumeActivity()方法原型如下: 位于ActivityThread類中

      1. void makeVisible() {  
      2.     if (!mWindowAdded) {  
      3.         ViewManager wm = getWindowManager();   // 獲取WindowManager對(duì)象  
      4.         wm.addView(mDecor, getWindow().getAttributes());  
      5.         mWindowAdded = true;  
      6.     }  
      7.     mDecor.setVisibility(View.VISIBLE); //使其處于顯示狀況  
      8. }  



           接下來(lái)就是,如何把我們已經(jīng)創(chuàng)建好的窗口通知給WindowManagerService ,以便它能夠把這個(gè)窗口顯示在屏幕上。

      關(guān)于這方面內(nèi)容大家可以去看鄧凡平老師的這篇博客《Android深入淺出之Surface[1]



      1. <pre></pre>  
      2. <pre></pre>  
      3. <pre></pre>  
      4. <pre></pre>  
      5. <pre></pre>  
      6. <pre></pre>  
      7. <pre></pre>  
      8. <pre></pre>  
      9. <pre></pre>  
      10. <pre></pre>  
      11. <pre></pre>  
      12. <pre></pre>  
      13. <pre></pre>  
      14. <pre></pre>  

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多