天天看點

Android控件架構以及setContentView()方法剖析

轉載請注明出處:

http://blog.csdn.net/qq347198688/article/details/52637908

本文出自【何嘉龍的部落格】

前言:

本篇部落格是在閱讀醫生的《Android群英傳》第三章總結出來的,在下正在學習進階中,有不足的地方希望大家能夠指出來。然後衷心向大家推薦這本書。

Android 控件架構

Android中的每個控件都會在界面中占得一塊矩形的區域,而在Android中,控件大緻被分為兩類,即ViewGroup控件與View控件。ViewGroup控件作為父控件可以包含多個View控件,并管理其包含的View控件。通過ViewGroup,整個界面上的控件形成了一個樹形結構,這也就是我們常說的控件樹,上層控件負責下層子控件的測量與繪制,并傳遞互動事件。通常在Activity中使用的findViewById()方法,就是在控件樹中以樹的深度優先周遊來查找對應元素。在每顆控件樹頂部,都有一個ViewParent對象,這就是整棵樹的核心,所有的互動管理事件都由它來統一排程和配置設定,進而可以對整個視圖進行整體控制。

View控件樹:

Android控件架構以及setContentView()方法剖析

通常情況下,在Activity中使用setContentView()方法來設定一個布局,在調用該方法後,布局内容才能真正顯示出來。那麼setContentView方法具體做了些什麼呢?首先我們來看一下Android界面的架構圖,如下所示:

Android控件架構以及setContentView()方法剖析

如圖所示,每個Activity都包含一個Window,在Android中Window對象通常由PhoneWindow來實作。PhoneWindow将一個DecorView設定為整個應用視窗的根View。DecorView作為視窗界面的頂層視圖,封裝了一些視窗操作的通用方法。可以說DecorView将要顯示的具體内容呈現在了PhoneWindow上,這裡面的所有View的監聽事件,都通過WindowManagerService來進行接收,并通過Activity對象來回調相應的OnClickListener。

activity、window和view之間的關系:

而當我們運作程式的時候,有一個setContentView()方法,Activity其實不是顯示視圖(直覺上感覺是它),實際上Activity調用了PhoneWindow的setContentView()方法,然後加載視圖,将視圖放到這個Window上,而Activity其實構造的時候初始化的是Window(PhoneWindow),Activity其實是個控制單元,即可視的人機互動界面。

打個比喻:

Activity是一個勞工,它來控制Window;Window是一面顯示屏,用來顯示資訊;View就是要顯示在顯示屏上的資訊,這些View都是層層重疊在一起(通過infalte()和addView())放到Window顯示屏上的。而LayoutInfalter就是用來生成View的一個工具,XML布局檔案就是用來生成View的原料。

activity調用setContentView其實是調用window的方法。讓我們來檢視源碼:

Activity中:

public void setContentView(int layoutResID) {
        getWindow().setContentView(layoutResID);
        initActionBar();
    }
           

在PhoneWindow類中:

@Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }
           

在了解實際上Activity調用了PhoneWindow的setContentView()方法後,再讓我們看到那幅界面架構圖,DecorView,它将螢幕分為兩個部分,一個是TitleView,另一個是ContentView。看到這裡,大家一定看到了一個非常熟悉的布局——ContentView。它是一個ID為content的FrameLayout,activity_main.xml就是設定在這樣的一個FrameLayout裡。

舉個例子讓大家了解一下:

Android控件架構以及setContentView()方法剖析

對應的xml檔案如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout                      xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="edu.whut.xucheng.job1.MainActivity">

    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="顯示手機資訊" />
</RelativeLayout>
           

可以看到,我們并沒有在xml檔案中寫入Actionbar或者是Toolbar,而我們的運作效果裡面就有。這是為什麼呢?大家回顧一下上面說的,DecorView被分為兩個部分,第一個是TitleView,由Actionbar或Toolbar組成。另一個就是ContentView,對應的是布局檔案裡面的内容。是以TitleView不是在布局檔案中定義的。

當然,我們也可以在布局檔案中定義自己的Toolbar,但必須要在代碼中加入requestWindowFeature(Window.FEARURE_NO_TITLE)隐藏系統自帶的TitleView。

歡迎大家提出意見,指責錯誤。

繼續閱讀