企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
### 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)