Android GUI之Activity、Window、View,androidactivity

來源:互聯網
上載者:User

Android GUI之Activity、Window、View,androidactivity

  相信大家在接觸Android之初就已經知道了Activity中的setContentView方法的作用了,很明顯此方法是用於為Activity填充相應的布局的。那麼,Activity是如何將填充的布局繪製出來的呢?實際上Activity將View的繪製與顯示交給了Window對象來處理,下面我們通過源碼來進行跟蹤分析。

  Activity的源碼如下,只給出我們關注的部分:

public class Activity extends ContextThemeWrapper        implements LayoutInflater.Factory2,        Window.Callback, KeyEvent.Callback,        OnCreateContextMenuListener, ComponentCallbacks2,        Window.OnWindowDismissedCallback {      ……    ……    private Window mWindow;    private WindowManager mWindowManager;    ……  /**     * Retrieve the current {@link android.view.Window} for the activity.     * This can be used to directly access parts of the Window API that     * are not available through Activity/Screen.     *     * @return Window The current window, or null if the activity is not     *         visual.     */    public Window getWindow() {        return mWindow;    }    ……    /**     * 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(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();    }    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, IVoiceInteractor voiceInteractor) {        attachBaseContext(context);        mFragments.attachActivity(this, mContainer, null);        mWindow = PolicyManager.makeNewWindow(this);              ……    }……}

PolicyManager的部分源碼:

public final class PolicyManager {    ……private static final IPolicy sPolicy;    static {        // Pull in the actual implementation of the policy at run-time       ……            sPolicy = (IPolicy)policyClass.newInstance();      ……    }    // Cannot instantiate this class    private PolicyManager() {}    // The static methods to spawn new policy-specific objects    public static Window makeNewWindow(Context context) {        return sPolicy.makeNewWindow(context);    }    ……}

Policy的部分源碼:

public class Policy implements IPolicy {   ……    public Window makeNewWindow(Context context) {        return new PhoneWindow(context);}……}

  從給出的源碼我們可以看到,Activity內部含有一個Window類型的對象mWindow,當我們調用setContentView方法時,實際上是委託給了Window對象進行處理。Window本身是一個抽象類別,它描述了android視窗的基本屬性和行為特徵。在activity的attach方法中通過mWindow = PolicyManager.makeNewWindow(this)建立了Window對象。通過追蹤代碼可知, PolicyManager.makeNewWindow(this)實際上是調用Policy中的makeNewWindow方法,在此方法中建立了一個PhoneWindow對象。而PhoneWindow正是Window的子類。他們的關係圖如下:

繼續追蹤源碼,PhoneWindow對Window的抽象方法setContentView(int layoutResId)進行了實現,具體源碼如下:

@Override    public void setContentView(int layoutResID) {        // 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)) {            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,                    getContext());            transitionTo(newScene);        } else {            mLayoutInflater.inflate(layoutResID, mContentParent);        }        final Callback cb = getCallback();        if (cb != null && !isDestroyed()) {            cb.onContentChanged();        }    }

  在這個方法中我們可以看到首先對mContentParent進行了判斷,如果為空白的話則調用installDecor方法,通過hasFeature判斷window是否具備某些特徵,如果視窗不含有FEATURE_CONTENT_TRANSITIONS特徵,則清空mContentParent中的所有子項目,為後面載入布局檔案到mContentParent中做好準備。通過後面的判斷,我們也可以看出無論走那個分支,其實都是對mContentParent布局內容做了更新。由此我們可以推斷出mContentParent其實就是我們自己的布局的存放容器,它在PhoneWindow中定義如下:

    // This is the view in which the window contents are placed. It is either    // mDecor itself, or a child of mDecor where the contents go.    private ViewGroup mContentParent;

  那麼mContentParent是在哪裡被建立的呢,很顯然是在方法installDecor中,方法installDecor的關鍵代碼如下:

    private void installDecor() {        if (mDecor == null) {            mDecor = generateDecor();           ……        }        if (mContentParent == null) {mContentParent = generateLayout(mDecor);            ……       }}

  在這個方法中,我們可以看到,首先對mDecor進行判斷,如果為空白在調用generateDecor方法產生mDecor對象,那麼mDecor對象是什麼呢?通過查看代碼,可以知道mDecor的類型為DecorView,此類型是定義在PhoneWindow中的一個內部類,它繼承了FrameLayout。緊接著判斷mContentParent是否為空白,為空白則調用generateLayout並通過傳入參數mDecor產生了mContentParent對象。在這個方法中通過應用的主題、視窗特徵等來確定使用的布局資源並將使用的布局添加mDecor中,而這些布局中都會含有一個id為content的ViewGroup(FrameLayout),此ViewGroup正是mContentParent,方法關鍵代碼如下:

protected ViewGroup generateLayout(DecorView decor) {        ……        View in = mLayoutInflater.inflate(layoutResource, null);        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));        mContentRoot = (ViewGroup) in;        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);       ……        return contentParent;    }

  由此我們可以確定,view的顯示處理順序為Activity->PhoneWindow->DecorView->ViewGroup(mContentView)->自訂的View(布局)。

  Activity中顯示視圖的階層,具體如下:

 

  疑問諮詢或技術交流,請加入官方QQ群: (452379712)

 

作者:傑瑞教育
出處:http://blog.csdn.net/jerehedu/ 
本文著作權歸煙台傑瑞教育科技有限公司和CSDN共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文串連,否則保留追究法律責任的權利。 

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.