zoukankan      html  css  js  c++  java
  • Android View体系(六)从源码解析Activity的构成

    前言

    本来这篇是要讲View的工作流程的,View的工作流程主要指的measure、layout、draw这三大流程,在讲到这三大流程之前我们有必要要先了解下Activity的构成,所以就有了这篇文章。

    1.从源码解析Activity的构成

    当我们写Activity时会调用setContentView()方法,来加载布局,来看看setContentView()方法是怎么实现的(Activity.java):

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

    这里调用了getWindow().setContentView(layoutResID),getWindow()指的是什么呢?接着往下看,getWindow()返回mWindow

    public Window getWindow() {
        return mWindow;
    }
    View Code

    在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);
    ...省略
    }
    View Code

    原来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();
           }
       }
    View Code

    在第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);  
           }
           ...省略
     } 
     ...省略          
    }
    View Code

    再接着追踪看看generateDecor()方法里写了什么:

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

    这里创建了一个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));
    ...省略
    
    }
    View Code

    第42行加载layoutResource的布局,来看看其中的一种布局R.layout.screen_title,这个文件在frameworksasecore es eslayout目录中(screen_title.xml)

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:fitsSystemWindows="true">
        <!-- Popout bar for action modes -->
        <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"
            style="?android:attr/windowTitleBackgroundStyle">
            <TextView android:id="@android:id/title" 
                style="?android:attr/windowTitleStyle"
                android:background="@null"
                android:fadingEdge="horizontal"
                android:gravity="center_vertical"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </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" />
    </LinearLayout>
    View Code

    上面的ViewStub是用来显示ActionBar的,下面的两个FrameLayout,一个是title用来显示标题,一个是content用来显示内容。

    2.图解Activity的构成

    看到如上的源码大家就知道了一个Activity包含一个window对象,这个对象是由PhoneWindow来实现的,PhoneWindow将DecorView做为整个应用窗口的根View,而这个DecorView又将屏幕划分为两个区域一个是TitleView一个是ContentView,而我们平常做应用所写的布局正是展示在ContentView中的。

  • 相关阅读:
    centos安装elasticsearch-rtf5.5.4
    docker的8个使用场景
    通过优化Gunicorn配置获得更好的性能
    django更换ORM连接处理(连接池)转
    单点登录,系统B如何辨别用户已登录系统A
    数据库Mysql的学习(六)-子查询和多表操作
    数据库Mysql的学习(五)-运算符与函数
    数据库Mysql的学习(四)-表的记录操作
    数据库Mysql的学习(三)-各种约束
    c和c++单链表
  • 原文地址:https://www.cnblogs.com/ganchuanpu/p/6034405.html
Copyright © 2011-2022 走看看