IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Activity与AppCompatActivity的setContentView的源码分析 -> 正文阅读

[移动开发]Activity与AppCompatActivity的setContentView的源码分析

Activity与AppCompatActivity的setContentView的源码分析

Activity 中的MainActivity extends AppcompatActivity 与 extends Activity的区别呢?

解答:
AppCompatActivity是继承自v4的FragmentAvtivity,并且加入了很多的新特性。这个可以很好的兼容老设备
且在AppCompatActivity和Activity的区别在于app运行后是否有ActionBar的区别,界面(appname显示或者不显示)。对程序本身没有什么影响。

首先是我们打开一个Android应用,映入眼帘的是MainActivity extends AppcompatActivty,这是现在比较高版本的Android studio的创建的方式。或许你们见MainActivity extends Activity的版本,今天我们就是关于两者的setContextView方法进行讲解。

这篇文章我们先从Activity的方式进行讲解。

首先我们看到Activity的setContentView方法源码
public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

由于上面的源码得到,setContentView是移交给了getWindow返回的对象进行setContentView方法的实现。然而getWindow返回的对象是什么呢?这不经让我们好奇!!
我们再去查看源码:

有以上得知,PhoneWindow是Window的唯一实现类。所以实现setContentView方法的是PhoneWindow,所以我们再去打开PhoneWindow的setContentView方法:(我截取了关键性代码)

@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);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
}

在以上代码中是否又有很多的疑惑呢?现在我来跟你慢慢来讲解。

我们首先看到的是一个判断语句,在语句里面我们会发现几个陌生的对象(对于想我这种小白来说是这样的):mContentParent 以及几个陌生的方法 installDecor removeAllViews,首先mContentParent是什么呢?其次installDecor removeAllViews方法有么作用呢? 在这我直接公布答案:mContentParent就是自己调用setContentView方法中传进来的那个的布局(是一个ViewGroup) 而installDecor是在判断mContentParent为空时候,去新建一个DecorView 我们之后会得知DecorView继承自FrameLayout(也是个ViewGroup)并且是Activity的根布局,为什么mContentParent为空建造DecorView呢?这就联想到mContentParent其实是嵌套在了DecorView中的一个子View。
private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            mDecor = generateDecor(-1);
            //.....
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
        }
    }
在代码中我们首先是判断mDecor是否为空(mDecor其实就是DecorView),就通过generateDecor方法生成一个DecorView接着就去generateLayout去生成一个mContentParent,所以我们去紧接着去看generateLayout去看一下怎么去生成mContentParent的
protected ViewGroup generateLayout(DecorView decor) {
        // Apply data from current theme.
        TypedArray a = getWindowStyle();
        int layoutResource;
        int features = getLocalFeatures();
      
        else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
           
            layoutResource = R.layout.screen_progress;
        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
                //加载资源
                layoutResource = R.layout.screen_custom_title;
        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
                layoutResource = res.resourceId;
                layoutResource = R.layout.screen_title;
        } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
            layoutResource = R.layout.screen_simple_overlay_action_mode;
        } else {
            layoutResource = R.layout.screen_simple;
        }

        mDecor.startChanging();
        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
        
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        if (contentParent == null) {
            throw new RuntimeException("Window couldn't find content container view");
        }
		//......
        mDecor.finishChanging();
        return contentParent;
    }

generateLayout()方法去根据Theme和style获取一个系统的布局LayoutResourse

在根据这个LayoutResourse去调用mDecor.onResoursesLoaded(mLayoutinflater,LayouResourse);将这个布局加载到mDecor中,之后通过findViewById方法获取到contentParent对象(其实是mContentParent)

我们点进findViewById方法:

@Nullable
    public <T extends View> T findViewById(@IdRes int id) {
        return getDecorView().findViewById(id);
    }```

这只是方法,我们还看见了出入了一个参数ID_ANDROID_CONTENT是什么呢?点进去看看:

```java
/**
     * The ID that the main layout in the XML layout file should have.
     */
    public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;

这就是说通过DecorView的find ViewById方法找到了com.android.internal.R.id.content的contentParent对象,这样也佐证了mContentParent是嵌套在mDecor中的。

我们再去回到最上面的generateLayout方法中,最后将contentParent返回,这样instalDecor方法就分析完了。这样就是DecorView和ContentParent都创建好了。

我们再回到PhoneWindow中的setContentView方法中,我们会看到一个代码
@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);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }
上面的mLayoutInflater.inflate(layoutResID, mContentParent);现在我们就知mContentParent就是上面mDecor创建返回的子view。而另外的参数是什么?很显然是我们层层传来的布局就好比MainActivity传来的R.layout.activity_main传入我们自己的布局并且加载到mContentView中去。以上就是Activity通过setContentView加载视图的过程:我们来总结一下:

在这里插入图片描述

图中水平箭头表示的是右面框里的内容是在左面框方法的内部执行的,竖直箭头表示下面的框是在上面框中方法执行结束后执行的。下面这张图展示了布局加载的流程:

在这里插入图片描述

以上就是我对Activity使用setContentView加载视图的理解。部分地方引用了其他资源,仅供大家学习,不做商用。欢迎大家来进行指正。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:32:44  更:2022-04-09 18:34:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 21:07:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码