当前位置: 首页 > news >正文

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,这个文件在frameworks\base\core\res\res\layout目录中(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中的。

相关文章:

  • EXCEL 读取
  • rip路由协议基本配置
  • [Unity3D]深度相机 Depth Camera
  • phpmyadmin安装教程及配置设置
  • 11.08---日记
  • 互斥量与信号量
  • 数据库备份那点事儿
  • maven 中使用jetty
  • 微软宣布Azure DNS全面通用
  • Flex 布局教程:语法篇
  • passwd命令--Linux命令应用大词典729个命令解读
  • 【阿里云资讯】马云为何还要做92届双11?
  • openstack出错记录
  • LAMP编译安装(四)——安装xcache-3.2.0
  • 启动sonar服务器报错:Cleaning or creating temp directory xxx\xxx\temp
  • [deviceone开发]-do_Webview的基本示例
  • 【翻译】babel对TC39装饰器草案的实现
  • ECMAScript6(0):ES6简明参考手册
  • IDEA常用插件整理
  • javascript从右向左截取指定位数字符的3种方法
  • Java精华积累:初学者都应该搞懂的问题
  • JDK 6和JDK 7中的substring()方法
  • js递归,无限分级树形折叠菜单
  • python 装饰器(一)
  • Service Worker
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • Vue2.0 实现互斥
  • vue-router的history模式发布配置
  • Wamp集成环境 添加PHP的新版本
  • 服务器之间,相同帐号,实现免密钥登录
  • 构造函数(constructor)与原型链(prototype)关系
  • 回顾 Swift 多平台移植进度 #2
  • 机器学习 vs. 深度学习
  • 七牛云 DV OV EV SSL 证书上线,限时折扣低至 6.75 折!
  • 如何选择开源的机器学习框架?
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • 应用生命周期终极 DevOps 工具包
  • 走向全栈之MongoDB的使用
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • (1)(1.13) SiK无线电高级配置(五)
  • (20050108)又读《平凡的世界》
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (Java)【深基9.例1】选举学生会
  • (java)关于Thread的挂起和恢复
  • (windows2012共享文件夹和防火墙设置
  • (ZT)一个美国文科博士的YardLife
  • (第27天)Oracle 数据泵转换分区表
  • (九十四)函数和二维数组
  • (力扣)1314.矩阵区域和
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (一)Neo4j下载安装以及初次使用
  • ./和../以及/和~之间的区别