Activity类:Android四大组件之一,是开发者最常用的一个组件
Window类:是一个抽象类,具有窗口管理的功能,实现类为PhoneWindow
View类:提供对View的操作,包括绘制测量等等
 
他们三个之间的关系便是Activity类通过Window组装View对象,然后把组装出来的对象交给系统去绘制
 
接下来我们从代码的角度分析一下这个过程
 
首先,我们在写Activity的时候,会重写系统提供的onCreate方法,然后调用setContentView来绑定页面布局
 
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.hello_word);
}

setContentView是Activity内定义的一个方法,但是主要功能,缺是由Window类来实现

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

getWindow这个函数返回来一个mWindow对象,这个mWindow对象是在attach函数中被初始化

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,
        Window window, ActivityConfigCallback activityConfigCallback) {
         //此处省略N行代码
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
         //此处省略N行代码
} 

由此可知,实现类便是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;
}
PhoneWindow内的setContentView会做两件事
一、安装DecorView
二、把Activity传递进来的resId加载进DecorView的content内
 
tips:
 
DecorView:是我们Android系统的屏幕所呈现的视图,包括上边状态栏,中心的内容区域,以及底部导航栏
 
Android内的DecorView是复用的,每次开启新的Activity的时候,会从上一个Activity处来获取之前的DecorView
新的Activity拿到这个DecorView后,会把content内的内容移除掉,然后补上自己的content,这样就实现了页面的切换。
 

接下来我分析一下安装DecorView的过程,由上可知,是通过installDecor函数触发的操作

private void installDecor() {
    mForceDecorInstall = false;
    if (mDecor == null) {
        mDecor = generateDecor(-1);
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    } else {
        mDecor.setWindow(this);
    }
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);

        // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
        mDecor.makeOptionalFitsSystemWindows();

        final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                R.id.decor_content_parent);

        if (decorContentParent != null) {
            mDecorContentParent = decorContentParent;
            mDecorContentParent.setWindowCallback(getCallback());
            if (mDecorContentParent.getTitle() == null) {
                mDecorContentParent.setWindowTitle(mTitle);
            }

            final int localFeatures = getLocalFeatures();
            for (int i = 0; i < FEATURE_MAX; i++) {
                if ((localFeatures & (1 << i)) != 0) {
                    mDecorContentParent.initFeature(i);
                }
            }

            mDecorContentParent.setUiOptions(mUiOptions);

            if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
                    (mIconRes != 0 && !mDecorContentParent.hasIcon())) {
                mDecorContentParent.setIcon(mIconRes);
            } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
                    mIconRes == 0 && !mDecorContentParent.hasIcon()) {
                mDecorContentParent.setIcon(
                        getContext().getPackageManager().getDefaultActivityIcon());
                mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
            }
            if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
                    (mLogoRes != 0 && !mDecorContentParent.hasLogo())) {
                mDecorContentParent.setLogo(mLogoRes);
            }

            // Invalidate if the panel menu hasn't been created before this.
            // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu
            // being called in the middle of onCreate or similar.
            // A pending invalidation will typically be resolved before the posted message
            // would run normally in order to satisfy instance state restoration.
            PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
            if (!isDestroyed() && (st == null || st.menu == null) && !mIsStartingWindow) {
                invalidatePanelMenu(FEATURE_ACTION_BAR);
            }
        } else {
            mTitleView = findViewById(R.id.title);
            if (mTitleView != null) {
                if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
                    final View titleContainer = findViewById(R.id.title_container);
                    if (titleContainer != null) {
                        titleContainer.setVisibility(View.GONE);
                    } else {
                        mTitleView.setVisibility(View.GONE);
                    }
                    mContentParent.setForeground(null);
                } else {
                    mTitleView.setText(mTitle);
                }
            }
        }

        if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
            mDecor.setBackgroundFallback(mBackgroundFallbackResource);
        }

        // Only inflate or create a new TransitionManager if the caller hasn't
        // already set a custom one.
        if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
            if (mTransitionManager == null) {
                final int transitionRes = getWindowStyle().getResourceId(
                        R.styleable.Window_windowContentTransitionManager,
                        0);
                if (transitionRes != 0) {
                    final TransitionInflater inflater = TransitionInflater.from(getContext());
                    mTransitionManager = inflater.inflateTransitionManager(transitionRes,
                            mContentParent);
                } else {
                    mTransitionManager = new TransitionManager();
                }
            }

            mEnterTransition = getTransition(mEnterTransition, null,
                    R.styleable.Window_windowEnterTransition);
            mReturnTransition = getTransition(mReturnTransition, USE_DEFAULT_TRANSITION,
                    R.styleable.Window_windowReturnTransition);
            mExitTransition = getTransition(mExitTransition, null,
                    R.styleable.Window_windowExitTransition);
            mReenterTransition = getTransition(mReenterTransition, USE_DEFAULT_TRANSITION,
                    R.styleable.Window_windowReenterTransition);
            mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, null,
                    R.styleable.Window_windowSharedElementEnterTransition);
            mSharedElementReturnTransition = getTransition(mSharedElementReturnTransition,
                    USE_DEFAULT_TRANSITION,
                    R.styleable.Window_windowSharedElementReturnTransition);
            mSharedElementExitTransition = getTransition(mSharedElementExitTransition, null,
                    R.styleable.Window_windowSharedElementExitTransition);
            mSharedElementReenterTransition = getTransition(mSharedElementReenterTransition,
                    USE_DEFAULT_TRANSITION,
                    R.styleable.Window_windowSharedElementReenterTransition);
            if (mAllowEnterTransitionOverlap == null) {
                mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(
                        R.styleable.Window_windowAllowEnterTransitionOverlap, true);
            }
            if (mAllowReturnTransitionOverlap == null) {
                mAllowReturnTransitionOverlap = getWindowStyle().getBoolean(
                        R.styleable.Window_windowAllowReturnTransitionOverlap, true);
            }
            if (mBackgroundFadeDurationMillis < 0) {
                mBackgroundFadeDurationMillis = getWindowStyle().getInteger(
                        R.styleable.Window_windowTransitionBackgroundFadeDuration,
                        DEFAULT_BACKGROUND_FADE_DURATION_MS);
            }
            if (mSharedElementsUseOverlay == null) {
                mSharedElementsUseOverlay = getWindowStyle().getBoolean(
                        R.styleable.Window_windowSharedElementsUseOverlay, true);
            }
        }
    }
}
这个函数很长,但是并不复杂
1.先通过generateDecor函数生成了一个mDecor对象,设置一些基础参数后便是初始化完成
2.在通过generateLayout函数,根据mDecor生成了mContentParent这个ViewGroup,就是所谓的内容区域,换句话说就是显示我们Activity内布局的地方
3.最后在根据系统的预装样式做一些修饰,便完成了DecorView的初始化
 

好了,我们思路继续回到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;
}
咱们通常程序内的Activity在启动的时候,DecorView是从LauncherActivity下传递过来的,所以就不用再执行install过程了,而是执行内容区域的清空view操作,然后通过inflate函数把Activity的resId加载进mContentParent对象内。
然后触发requestApplyInsets函数进行重绘刷新屏幕
最后触发onContentChanged监听,这个Callback接口在Activity内有实现
 
最后在总结一下本篇的内容
Activity内包含了Window对象,很多功能也是借助Window对象得以实现

Window对象下维护了一个DecorView

如果有错误或者疑问,请在评论区指出,我会即使更正,共同学习,共同进步,谢谢支持!

Activity、Window、View三者之间的联系的更多相关文章

  1. Activity Window View的关系

    http://blog.csdn.net/chiuan/article/details/7062215 http://blog.163.com/fenglang_2006/blog/static/13 ...

  2. 底层剖析 Window 、Activity、 View 三者关系

    不管工作几年的 Android 工程师,或多或少都听说过 Window 的概念,并且隐隐约约感觉它在 Activity 与 View 之间应该发挥着某种连接的作用.但是如果需要说出这 3 者之间的关系 ...

  3. activity window view 关系

    1.Activity , Window和View的关系是什么? 跟踪Activity的源码就会发现:Activity.attch() -> PolicyManager -> Policy ...

  4. Activity Window View WindowManager关系&Touch事件分发机制

    http://www.cnblogs.com/linjzong/p/4191891.html https://www.cnblogs.com/kest/p/5141817.html https://b ...

  5. android中activity,window,view之间的关系

    activity:控制单元 window:承载模型 view:显示视图 几个小tip: 1.一个 Activity 构造的时候一定会构造一个 Window(PhoneWindow),并且只有一个 2. ...

  6. android 中的 window,view,activity具体关系

    通过讨论这个问题,我们能够见识到google是对面向对象模式的理解,能够理解android底层的一些调用.这也是一道很常见的面试题. 我们这篇文章就来解决这四个问题: Android  中view的显 ...

  7. View, Activity, Window

    View, Activity, Window 2010-03-02 10:42:56|  分类: android|举报|字号 订阅     对于屏幕显示而言,整个是window,这个window里显示 ...

  8. Window系统、主函数和窗体函数这三者之间的关系

    理解Window系统.主窗体.窗体函数这三者之间的关系,对于编写Windows程序十分重要. 主函数和窗体函数都是由Windows系统来调用的函数.仅仅只是主函数是程序启动之后.系统首先调用的函数: ...

  9. Activity和View的区别:

    Activity和View的区别: activity相当于控制部分,view相当于显示部分.两者之间是多对多的关系,所有东西必须用view来显示.  viewGroup继承自view,实现了ViewM ...

随机推荐

  1. 使用 ASP.NET Core MVC 创建 Web API(五)

    使用 ASP.NET Core MVC 创建 Web API 使用 ASP.NET Core MVC 创建 Web API(一) 使用 ASP.NET Core MVC 创建 Web API(二) 使 ...

  2. RabbitMQ 消息队列 入门 第一章

    RabbitMQ : 官网:https://www.rabbitmq.com/ GitHub:https://github.com/rabbitmq?q=rabbitmq 第一步安装: 点击  htt ...

  3. C#-Xamarin的Android项目开发(三)——发布、部署、打包

    前言 部署,通常的情况下,它其实也是项目开发的一个难点. 为什么这么说呢?因为,它不是代码开发,所以很多开发者本能的拒绝学习它. 并且一个项目配置好一次以后,部署的步骤和部署的人通常很固定,所以大部分 ...

  4. 【转载】C#工具类:实现文件操作File的工具类

    在应用程序的开发中,文件操作的使用基本上是必不可少的,FileStream类.StreamWriter类.Directory类.DirectoryInfo类等都是文件操作中时常涉及到的类,我们可以通过 ...

  5. 2018-09-15 Java源码英翻中库以及服务原型

    服务很简单, 只为演示这个库, 源码在: program-in-chinese/code_translator_service. 在Postman测试效果: 演示服务地址: 74.91.17.250: ...

  6. ArcPy 批量给shp字段赋值

    工作中需要做大量图层的拼接,为了在拼接完成后还能知道原始数据文件是什么,所以写了个Python脚本对每个图层的SOURCE字段进行赋值. 附上Python代码: # -*- coding: utf-8 ...

  7. 2018-12-25 VS Code英汉词典v0.0.8: 批量翻译文件部分命名

    续前文: VS Code英汉词典进化效果演示: 翻译文件所有命名 vscode"英汉词典"插件地址: 官方链接 现在实现的效果比之前的演示差很多, 因为executeDocumen ...

  8. Postman 安装

    前言 安装前的准备: 1.Chrome 浏览器的扩展插件来进行的安装,并非单独应用程序. 2.电脑上已经安装了 Chrome 浏览器 3.本文章适用操作系统  window7 一,非官方安装 个人不建 ...

  9. Exp2后门原理与实践 20164312马孝涛

    实验内容 使用netcat获取主机操作Shell,cron启动 (0.5分) 使用socat获取主机操作Shell, 任务计划启动 (0.5分) 使用MSF meterpreter(或其他软件)生成可 ...

  10. 有趣的 box-decoration-break

    这两天接触到一个很有意思的 CSS 属性 -- box-decoration-break.下面就一起去一探究竟. 因为 MDN 上关于这个属性,没有中文文档,所以一直在想一个合理贴切的中文翻译.直译一 ...