Android View體系(六)從源碼解析Activity的構成

來源:互聯網
上載者:User

Android View體系(六)從源碼解析Activity的構成

相關文章
Android View體系(一)視圖座標系
Android View體系(二)實現View滑動的六種方法
Android View體系(三)屬性動畫
Android View體系(四)從源碼解析Scroller
Android View體系(五)從源碼解析View的事件分發機制

前言

本來這篇是要講View的工作流程的,View的工作流程主要指的measure、layout、draw這三大流程,在講到這三大流程之前我們有必要要先瞭解下Activity的構成,所以就有了這篇文章。

1.從源碼解析Activity的構成

當我們寫Activity時會調用setContentView()方法,來載入布局,來看看setContentView()方法是怎麼實現的(Activity.java):

public void setContentView(@LayoutRes int layoutResID) {        getWindow().setContentView(layoutResID);        initWindowDecorActionBar();    }

這裡調用了getWindow().setContentView(layoutResID),getWindow()指的是什麼呢?接著往下看,getWindow()返回mWindow:

    public Window getWindow() {        return mWindow;    }

在Activity的attach()方法發現mWindow:

  final void attach(Context context, ActivityThread aThread,            Instrumentation instr, IBinder token, int ident,            Application application, Intent intent, ActivityInfo info,            CharSequence title, Activity parent, String id,            NonConfigurationInstances lastNonConfigurationInstances,            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {        attachBaseContext(context);        mFragments.attachHost(null /*parent*/);        mWindow = new PhoneWindow(this);...省略}

原來mWindow指的就是PhoneWindow,PhoneWindow是繼承抽象類別Window的,這樣就知道getWindow()得到的是一個PhoneWindow,我們來看看PhoneWindow.java的setContentView()方法(PhoneWindow.java):

 @Override    public void setContentView(View view, ViewGroup.LayoutParams params) {        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window        // decor, when theme attributes and the like are crystalized. Do not check the feature        // before this happens.        if (mContentParent == null) {            installDecor();        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {            mContentParent.removeAllViews();        }        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {            view.setLayoutParams(params);            final Scene newScene = new Scene(mContentParent, view);            transitionTo(newScene);        } else {            mContentParent.addView(view, params);        }        final Callback cb = getCallback();        if (cb != null && !isDestroyed()) {            cb.onContentChanged();        }    }

在第5行看到了 installDecor()方法,來看看這個方法裡寫了什麼:

 if (mDecor == null) {            mDecor = generateDecor();            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);            mDecor.setIsRootNamespace(true);            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);            }        }        if (mContentParent == null) {            mContentParent = generateLayout(mDecor);          }        ...省略  }   ...省略           }

再接著追蹤看看generateDecor()方法裡寫了什麼:

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

這裡建立了一個DecorView,這個DecorView就是Activity中的根View。接著查看DecorView的源碼,發現DecorView是PhoneWindow類的內部類,並且繼承FrameLayout。我們再來看看第10行generateLayout()方法:

 protected ViewGroup generateLayout(DecorView decor) {...省略        //根據不同的情況載入不同的布局給layoutResource        int layoutResource;        int features = getLocalFeatures();        // System.out.println("Features: 0x" + Integer.toHexString(features));        if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {            if (mIsFloating) {                TypedValue res = new TypedValue();                getContext().getTheme().resolveAttribute(                        com.android.internal.R.attr.dialogTitleIconsDecorLayout, res, true);                layoutResource = res.resourceId;            } else {                layoutResource = com.android.internal.R.layout.screen_title_icons;            }            // XXX Remove this once action bar supports these features.            removeFeature(FEATURE_ACTION_BAR);            // System.out.println("Title Icons!");        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {            // Special case for a window with only a progress bar (and title).            // XXX Need to have a no-title version of embedded windows.            layoutResource = com.android.internal.R.layout.screen_progress;            // System.out.println("Progress!");        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {            // Special case for a window with a custom title.            // If the window is floating, we need a dialog layout            if (mIsFloating) {                TypedValue res = new TypedValue();                getContext().getTheme().resolveAttribute(                        com.android.internal.R.attr.dialogCustomTitleDecorLayout, res, true);                layoutResource = res.resourceId;            } else {                layoutResource = com.android.internal.R.layout.screen_custom_title;            }            // XXX Remove this once action bar supports these features.            removeFeature(FEATURE_ACTION_BAR);...省略 mDecor.startChanging();        //將layoutResource載入到View中並添加到DecorView中        View in = mLayoutInflater.inflate(layoutResource, null);        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));...省略}

第42行載入layoutResource的布局,來看看其中的一種布局R.layout.screen_title,這個檔案在frameworks\base\core\res\res\layout目錄中(screen_title.xml)

<code class=" hljs xml"><linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:fitssystemwindows="true">    <!--{cke_protected}{C}%3C!%2D%2D%20Popout%20bar%20for%20action%20modes%20%2D%2D%3E-->    <viewstub android:id="@+id/action_mode_bar_stub" android:inflatedid="@+id/action_mode_bar" android:layout="@layout/action_mode_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="?attr/actionBarTheme">    <framelayout android:layout_width="match_parent" android:layout_height="?android:attr/windowTitleSize">        <textview android:id="@android:id/title" android:background="@null" android:fadingedge="horizontal" android:gravity="center_vertical" android:layout_width="match_parent" android:layout_height="match_parent">    </textview></framelayout>    <framelayout android:id="@android:id/content" android:layout_width="match_parent" android:layout_height="0dip" android:layout_weight="1" android:foregroundgravity="fill_horizontal|top" android:foreground="?android:attr/windowContentOverlay"></framelayout></viewstub></linearlayout></code>

上面的ViewStub是用來顯示ActionBar的,下面的兩個FrameLayout,一個是title用來顯示標題,一個是content用來顯示內容。

2.圖解Activity的構成

看到如上的源碼大家就知道了一個Activity包含一個window對象,這個對象是由PhoneWindow來實現的,PhoneWindow將DecorView做為整個應用視窗的根View,而這個DecorView又將螢幕劃分為兩個地區一個是TitleView一個是ContentView,而我們平常做應用所寫的布局正是展示在ContentView中的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.