### Android 中window 、view、 Activity的关系 ###
在Activity类中,启动activity,通过`startActivityForResult()`方法,这是通过外部启动Activity,实际上启动核心是内部的一个final方法attach(),attach()方法通过PolicyManager实现一个接口Ipolicy,实现这个接口的类是Policy这个类,实现的方法是`makeNewWindow(Context context)`,`mWindow = PolicyManager.makeNewWindow(this);`创造一个窗体,该窗体是PhoneWindow类型的窗体,PhoneWindow 又继承于Window,Activity在启动时实例化了一个PhoneWindow的窗体,PhoneWindow 又在构造函数时实例化了ViewGroup,ViewGroup是view的一个子类。以后添加view通过ViewGroup,同时构造时通过LayoutInflater()把layout资源文件进行加载,setContentView()进行界面的呈现,也是按照这样的一个顺序,最终调用的是PhoneWindow的setContentView(),之后分2种情况,一种是传的参数直接就是view,最终通过ViewGroup来添加一个view,另一种传的参数是R的资源文件,此时会用到LayoutInflater()这样的一个类,把资源文件构造实例化,最终还是实例化view的这样一个对象,还是调用ViewGroup将view呈现。
- 下图是activity、window、view之间的联系
:-: ![](https://img.kancloud.cn/13/84/138452144ef12eea7811d12788429cb3_654x258.png)
图一、分发事件的方法在Activity、View以及ViewGroup中存在关系
:-: ![](https://img.kancloud.cn/f0/27/f027120f562a667c622092a747298cfc_1152x648.jpg)
图二、UI界面架构图
:-: ![](https://img.kancloud.cn/c2/d3/c2d39ad9c8518a042f1363985d7591cb_927x607.png)
图三、Activity与WindowView的关联代码层面流程图
- Activity的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) {
attachBaseContext(context);
mFragments.attachActivity(this, mContainer, null);
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
if (voiceInteractor != null) {
if (lastNonConfigurationInstances != null) {
mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
} else {
mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
Looper.myLooper());
}
}
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
~~~
----------
Activity启动的时候,即调用attach()方法会得到一个window,而phoneWindow是window唯一一个实现的子类
- Activity的setContentView()方法
~~~
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
public void setContentView(View view) {
getWindow().setContentView(view);
initWindowDecorActionBar();
}
public void setContentView(View view, ViewGroup.LayoutParams params) {
getWindow().setContentView(view, params);
initWindowDecorActionBar();
}
~~~
从该方法可以看出先得到当前的一个窗体getWindow()方法即一个Activity一定会有一个当前的window,当Activity实例化时,一定会实例化一个并且仅有一个window,window本身不是显示的视图,只是一个窗户玻璃,窗户玻璃上的窗花(实际上是view)才是真正的视图,而且window实际上是其唯一的一个实例化的子类PhoneWindow,之后调用phoneWindow的setContentView方法,该方法内部会有一个mContentParent.addView(view, params)方法,来添加view视图,而这个窗花怎么裁剪和贴到玻璃呢,是通过LayoutInflater()和addView()。
**Activity相当于一个工人,该工人来建造一个窗户phoneWindow,这个窗户phoneWindow有一个viewRoot(view 、viewGroup),根视图,在根视图上面就要添加一个一个的view,通过 mContentParent.addView(view, params);来达到我们的想要的效果,mContentParent是一个viewGroup(),当我们点击界面的某一个控件时,实际上windowManagerService接收到这个讯息,来回调Activity的方法,比如onKeyDown()方法。Activity是控制单元,window是承载模型,view才是真正的显示视图**。
*****
总结:就是 **Activity会调用PhoneWindow的setContentView()将layout布局添加到DecorView上,而此时的DecorView就是那个最底层的View。然后通过LayoutInflater.infalte()方法加载布局生成View对象并通过addView()方法添加到Window上,(一层一层的叠加到Window上)所以,Activity其实不是显示视图,View才是真正的显示视图**。
>[success]注:一个Activity构造的时候只能初始化一个Window(PhoneWindow),另外这个PhoneWindow有一个View容器 mContentParent,这个View容器是一个ViewGroup,是最初始的根视图,然后通过addView方法将View一个个层叠到mContentParent上,这些层叠的View最终放在Window这个载体上面。
*****
- phonewindow的setContentView有3种重载形式
~~~
@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();
}
}
@Override
public void setContentView(View view) {
setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
@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和ViewGroup
Android系统中的所有UI类都是建立在View和ViewGroup这两个类的基础上的。所有View的子类成为”Widget”,所有 ViewGroup的子类成为”Layout”。View和ViewGroup之间采用了组合设计模式,可以使得“部分-整体”同等对待。 ViewGroup作为布局容器类的最上层,布局容器里面又可以有View和ViewGroup。
- LayoutInflater,LayoutInflater.inflate()这两个是什么意思?
LayoutInflater是一个用来实例化XML布局文件为View对象的类
LayoutInflater.infalte(R.layout.test,null)用来从指定的XML资源中填充一个新的View
- Activity是Android的显示视图么?
- 显然不是,view才是真正的显示视图
- Activity是window的容器,如果应用程序不调用Activity的setContentView()来设置该窗口显示的内容,那么该程序将显示一个窗口,Activity包含一个setTheme()方法来设置其窗口的风格。
- 参考链接
- [Android Activity 、 Window 、 View之间的关系 ](http://blog.csdn.net/u011733020/article/details/49465707)
- [Android_UI控件之Activity、Window、View之间的关系](http://www.cnblogs.com/webapplee/p/3774041.html)
- [麦子学院sundy老师视频讲解](http://v.youku.com/v_show/id_XODc1NjI5NTM2.html)
- 创建UML视图
- [参考1](http://www.cnblogs.com/handsome1013/p/5534677.html)
- [参考2](http://www.cnblogs.com/daizhj/archive/2008/04/14/1153121.html)
- 前言
- Android系统的体系结构
- Dalvik VM 和 JVM 的比较
- Android 打包应用程序并安装的过程
- Android ADB工具
- Android应用开发
- Android UI相关知识总结
- Android 中window 、view、 Activity的关系
- Android应用界面
- Android中的drawable和bitmap
- AndroidUI组件adapterView及其子类和Adapter的关系
- Android四大组件
- Android 数据存储
- SharedPreference
- Android应用的资源
- 数组资源
- 使用Drawable资源
- Material Design
- Android 进程和线程
- 进程
- 线程
- Android Application类的介绍
- 意图(Intent)
- Intent 和 Intent 过滤器(Google官网介绍)
- Android中关于任务栈的总结
- 任务和返回栈(官网译文)
- 总结
- Android应用安全现状与解决方案
- Android 安全开发
- HTTPS
- 安卓 代码混淆与打包
- 动态注入技术(hook技术)
- 一、什么是hook技术
- 二、常用的Hook 工具
- Xposed源码剖析——概述
- Xposed源码剖析——app_process作用详解
- Xposed源码剖析——Xposed初始化
- Xposed源码剖析——hook具体实现
- 无需Root也能Hook?——Depoxsed框架演示
- 三、HookAndroid应用
- 四、Hook原生应用程序
- 五、Hook 检测/修复
- Android 应用的逆向与加固保护技术
- OpenCV在Android中的开发
- Android高级开发进阶
- 高级UI
- UI绘制流程及原理
- Android新布局ConstraintLayout约束布局
- 关键帧动画
- 帧动画共享元素变换
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
- 为什么 Android 要采用 Binder 作为 IPC 机制?
- JVM 中一个线程的 Java 栈和寄存器中分别放的是什么?
- Android源码的Binder权限是如何控制?
- 如何详解 Activity 的生命周期?
- 为什么Android的Handler采用管道而不使用Binder?
- ThreadLocal,你真的懂了吗?
- Android屏幕刷新机制