android系統啓動框架、Activity界面顯示過程詳解

1、Android系統框架java

      android的系統架構和其操做系統同樣,採用了分層的架構。從架構圖看,android分爲四個層,從高層到低層分別是應用程序層、應用程序框架層、系統運行庫層和linux核心層。盜圖以下:linux

                                                  

具體每層的功能介紹以下:android

     (1) 應用程序層瀏覽器

      該層提供一些核心應用程序包,例如電子郵件、短信、日曆、地圖、瀏覽器和聯繫人管理等。同時,開發者能夠利用Java語言設計和編寫屬於本身的應用程序,而這些程序與那些核心應用程序彼此平等、友好共處。安全

     (2)應用程序框架層網絡

     該層是Android應用開發的基礎,開發人員大部分狀況是在和她打交道。應用程序框架層包括活動管理器、窗口管理器、內容提供者、視圖系統、包管理器、電話管理器、資源管理器、位置管理器、通知管理器和XMPP服務十個部分。在Android平臺上,開發人員能夠徹底訪問核心應用程序所使用的API框架。而且,任何一個應用程序均可以發佈自身的功能模塊,而其餘應用程序則可使用這些已發佈的功能模塊。基於這樣的重用機制,用戶就能夠方便地替換平臺自己的各類應用程序組件。架構

     (3) 系統庫和Android運行時app

     系統庫包括九個子系統,分別是圖層管理、媒體庫、SQLite、OpenGLEState、FreeType、WebKit、SGL、SSL和libc。Android運行時包括核心庫和Dalvik虛擬機,前者既兼容了大多數Java語言所須要調用的功能函數,又包括了Android的核心庫,好比android.os、android.net、android.media等等。後者是一種基於寄存器的java虛擬機,Dalvik虛擬機主要是完成對生命週期的管理、堆棧的管理、線程的管理、安全和異常的管理以及垃圾回收等重要功能。框架

     (4) Linux內核ide

     Android核心系統服務依賴於Linux2.6內核,如安全性、內存管理、進程管理、網絡協議棧和驅動模型。Linux內核也是做爲硬件與軟件棧的抽象層。驅動:顯示驅動、攝像頭驅動、鍵盤驅動、WiFi驅動、Audio驅動、flash內存驅動、Binder(IPC)驅動、電源管理等。

      Android的系統架構採用分層架構的思想,架構清晰,井井有條,協同工做。所以,若想從事Android應用開發,則研究研究Android的應用框架層和應用程序層;若想從事Android系統開發,那研究下Android系統庫和Android運行時;若想從事Android驅動開發,那試着看看Android的Linux內核。下面分別介紹android系統啓動流程和Activity界面顯示流程:

2、Android系統啓動流程

      衆所周知,在Linux中,它的啓動能夠歸爲一下幾個流程: Boot Loader——>初始化內核——>建立init進程——>根據inittable文件執行其餘的啓動項——>..... 。

      由此可知,當初始化內核以後,就會啓動一個至關重要的祖先進程,也就是init進程,在Linux中全部的進程都是由init進程直接或間接fork出來的。而對於Android來講,前面的流程都是同樣的:

 (1)當init進程建立以後,會fork出一個Zygote進程,這個進程是全部Java進程的父進程。咱們知道,Linux是基於C的,而Android是基於Java的(固然底層也是C);

 (2)而後fork出一個Zygote Java進程用來fork出其餘的進程。當Zygote(孵化進程)被初始化的時候,會fork出System Server進程,這個進程在整個的Android進程中是很是重要的一個,地位和Zygote等同,它是屬於Application Framework層的,Android中的全部服務,例如AMS, WindowsManager, PackageManagerService等等都是由這個SystemServer fork出來的。因此它的地位可見一斑;

 (3)當System Server進程開啓的時候,就會初始化AMS,同時,會加載本地系統的服務庫,建立系統上下文,建立ActivityThread及開啓各類服務等等。而在這以後,就會開啓系統的Launcher程序,完成系統界面的加載與顯示;

 (4)系統啓動完成後,當咱們點擊屏幕時,觸摸屏的兩層電極會鏈接在一塊兒,也就產生了一個電壓並經過對應的驅動把當前按壓點的XY座標傳給android系統。系統在獲取到XY值的時候,就會對按壓點的範圍進行一個判斷,若是肯定按壓點處於一個APP圖標或者是Button等等的範圍中時,操做系統也就會認爲用戶當前已經點擊了這個東西,啓動對應的監聽。而當系統判斷咱們點擊的是APP圖標時,該App就由Launcher開始啓動了;

  (5)當開始啓動時,Launcher進程會採用Binder的方式向AMS(Activity Manager Server)發出startActivity請求;

  (6)AMS在接收到請求以後,就會經過Socket向Zygote進程發送建立進程的請求;

  (7)Zygote進程會fork出新的子進程(APP進程);

  (8)隨後APP進程會再向AMS發起一次請求,AMS收到以後通過一系列的準備工做再回傳請求;

  (9)APP進程收到AMS返回的請求後,會利用Handler向主線程(即UI線程)發送LAUNCH_ACTIVITY消息;

注:主線程(也即ActivityThread)裏面存在一個main()方法,這也是APP的真正入口,當APP啓動時,就會啓動ActivityThread中的main方法,在main方法中系統會經過Looper.prepareMainLooper()來建立主線程的Looper以及MessageQueue,並經過Looper.loop來開啓消息循環。

 (10)主線程在收到消息以後,就建立目標Activity,並回調onCreate()/onStart()/onResume()等方法,UI渲染結束後即可以看到App主界面。

3、界面顯示流程

setContentView() 

   在Activity的onCreate()方法中,第一句便是寫setContentView(),它的具體實現和功能如何呢?這裏就要對你當前繼承的Activity分類了:

 (1) 若是是繼承的Activity,那麼setContentView源碼是這樣的:

 

    /**
    * Set the activity content from a layout resource. The resource will be
    * inflated, adding all top-level views to the activity.
    *
    * @param layoutResID Resource ID to be inflated.
    *
    * @see #setContentView(android.view.View)
    * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
    */
    public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
    }
    /**
    * Set the activity content to an explicit view. This view is placed
    * directly into the activity's view hierarchy. It can itself be a complex
    * view hierarchy. When calling this method, the layout parameters of the
    * specified view are ignored. Both the width and the height of the view are
    * set by default to {@link ViewGroup.LayoutParams#MATCH_PARENT}. To use
    * your own layout parameters, invoke
    * {@link #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}
    * instead.
    *
    * @param view The desired content to display.
    *
    * @see #setContentView(int)
    * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
    */
    public void setContentView(View view) {
    getWindow().setContentView(view);
    initWindowDecorActionBar();
    }
    /**
    * Set the activity content to an explicit view. This view is placed
    * directly into the activity's view hierarchy. It can itself be a complex
    * view hierarchy.
    *
    * @param view The desired content to display.
    * @param params Layout parameters for the view.
    *
    * @see #setContentView(android.view.View)
    * @see #setContentView(int)
    */
    public void setContentView(View view, ViewGroup.LayoutParams params) {
    getWindow().setContentView(view, params);
    initWindowDecorActionBar();
    }

 

      從以上代碼能夠看出一共存在着3個重載函數,且無論你調用哪個,最後都會調用到initWindowDecorActionBar()這個方法。 由setContentView上面的註釋可知,它會按照一個layout 佈局資源去設置Activity的內容,而這個佈局資源將會被引入而後添加全部頂級的Views到這個Activity當中。下圖copy了一張Activity層級圖:

                                                     

      由上圖可知,最底層是Activity,它包含裏面的全部東西,再上一層是一個PhoneWindow,這個PhoneWindow是由Window類派生出來的,每個PhoneWindow中都含有一個DecorView對象,Window是一個抽象類。 再上面一層就是一個DecorView,我理解這個DecorView就是一個ViewGroup,就是裝View的容器。 且在DecoreView中,最上面的View就是咱們的TitleActionBar,下面就是咱們要設置的content。因此在上面的initWindowDecorActionBar就能猜到是什麼意思了吧。而在initWindowDecorActionBar方法中,有下面一段代碼:

    /**
    * Creates a new ActionBar, locates the inflated ActionBarView,
    * initializes the ActionBar with the view, and sets mActionBar.
    */
    private void initWindowDecorActionBar() {
    Window window = getWindow();
    // Initializing the window decor can change window feature flags.
    // Make sure that we have the correct set before performing the test below.
    window.getDecorView();
    if (isChild() || !window.hasFeature(Window.FEATURE_ACTION_BAR) || mActionBar != null) {
    return;
    }
    mActionBar = new WindowDecorActionBar(this);
    mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp);
    mWindow.setDefaultIcon(mActivityInfo.getIconResource());
    mWindow.setDefaultLogo(mActivityInfo.getLogoResource());
    }

      注意上面的window.getDecoreView()方法的註釋,該方法會設置一些window的標誌位,而當這個方法執行完以後,就不再能更改了,這也就是爲何不少第三方SDK設置window的標誌位時必定要求要在setContentView方法前調用。
(2)對於一個新的AppcompatActivity,這個Activity裏面包含了一些新特性。在AppcompatActivity中,setContentView是這樣的:

    @Override
    public void setContentView(@LayoutRes int layoutResID) {
    getDelegate().setContentView(layoutResID);
    }
    @Override
    public void setContentView(View view) {
    getDelegate().setContentView(view);
    }
    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
    getDelegate().setContentView(view, params);
    }

      同樣的3個重載函數,只是裏面沒有了上面的那個init方法,取而代之的是一個getDelegate().setContentView,delegate(即委託/回調)的源碼是這樣的:

    /**
    * @return The {@link AppCompatDelegate} being used by this Activity.
    */
    @NonNull
    public AppCompatDelegate getDelegate() {
    if (mDelegate == null) {
    mDelegate = AppCompatDelegate.create(this, this);
    }
    return mDelegate;
    }
    而在AppCompatDelegate.Create方法中,則會返回一個頗有意思的東西:
    /**
    * Create a {@link android.support.v7.app.AppCompatDelegate} to use with {@code activity}.
    *
    * @param callback An optional callback for AppCompat specific events
    */
    public static AppCompatDelegate create(Activity activity, AppCompatCallback callback) {
        return create(activity, activity.getWindow(), callback);
    }
    private static AppCompatDelegate create(Context context, Window window,
                          AppCompatCallback callback) {
       final int sdk = Build.VERSION.SDK_INT;
      if (sdk >= 23) {
        return new AppCompatDelegateImplV23(context, window, callback);
      } else if (sdk >= 14) {
        return new AppCompatDelegateImplV14(context, window, callback);
      } else if (sdk >= 11) {
        return new AppCompatDelegateImplV11(context, window, callback);
      } else {
        return new AppCompatDelegateImplV7(context, window, callback);
      }
   }

 findViewById()

     咱們經過一個findViewById方法能夠實現對象的綁定,那它底層到底是怎麼實現的呢?findViewById根據繼承的Activity類型的不一樣也存在着區別:

(1)咱們的Activity繼承Activity類時

    /**
    * Finds a view that was identified by the id attribute from the XML that
    * was processed in {@link #onCreate}.
    *
    * @return The view if found or null otherwise.
    */
    @Nullable
    public View findViewById(@IdRes int id) {
      return getWindow().findViewById(id);
    }

      從源碼來看,findViewById的功能是經過一個view的id屬性查找view。它一樣包含getWindow()方法,說明findViewById()實際上Activity把它也是交給了本身的window來作。而對於getWindow()中的函數代碼以下:

    /**
    * Finds a view that was identified by the id attribute from the XML that
    * was processed in {@link android.app.Activity#onCreate}. This will
    * implicitly call {@link #getDecorView} for you, with all of the
    * associated side-effects.
    *
    * @return The view if found or null otherwise.
    */
    @Nullable
    public View findViewById(@IdRes int id) {
    return getDecorView().findViewById(id);
    }

      由以上代碼能夠看出,又調用了getDecorView的findViewById()方法,這也至關因而一個層層傳遞的過程,由於DecorView能夠理解爲就是一個ViewGroup,而當運行getDecorView().findViewById()方法時,就會運行View裏面的findViewById方法。它會使用這個被給予的id匹配子View的Id,若是匹配,就返回這個View,完成View的綁定。代碼以下:

    /**
    * Look for a child view with the given id. If this view has the given
    * id, return this view.
    *
    * @param id The id to search for.
    * @return The view that has the given id in the hierarchy or null
    */
    @Nullable
    public final View findViewById(@IdRes int id) {
    if (id < 0) {
    return null;
    }
    return findViewTraversal(id);
    }
    /**
    * {@hide}
    * @param id the id of the view to be found
    * @return the view of the specified id, null if cannot be found
    */
    protected View findViewTraversal(@IdRes int id) {
    if (id == mID) {
    return this;
    }
    return null;
    }

    由以上分析可知,Activity中的findViewById()調用過程是這樣的: Activity -> Window -> DecorView -> View。

相關文章
相關標籤/搜索