当前位置: 首页 > 科技观察

理性分析Window、Activity、DecorView、ViewRoot之间的关系

时间:2023-03-22 17:21:20 科技观察

文末,本文转载自微信公众号《Android开发编程》,作者Android开发编程。转载本文请联系Android开发编程公众号。前言Activity与window、DecorView、viewRoot是什么关系?今天我们就来讲解一下,让你在面试的时候游刃有余;一、基本概念介绍1、ActivityActivity负责控制生命周期和处理事件;负责协调视图的添加和显示,并通过一些回调方法与Window和View进行交互;一个Activity包含一个Window,而Window实际上控制着view,Window真正代表了一个窗口;协调视图的添加和显示,通过回调与Window和View进行交互;2.Window窗口是视图的承载者,是一个抽象类;Activity中持有的其实是PhoneWindow,它是Window的一个子类;Window通过WindowManager加载一个DecorView到Window中,并将DecorView交给ViewRoot;3.DecorViewDecorView的父类是FrameLayout,是AndroidView树的根节点;里面包含了一个垂直的LinearLayout,它分为三部分,上半部分是一个ViewStub,延迟加载视图(ActionBar,根据Theme设置),中间部分是标题栏(根据Theme设置,有些布局做没有),下面是内容栏。setContentView设置的布局文件实际上是添加到内容栏中的;ViewGroupcontent=(ViewGroup)findViewById(android.R.id.content);ViewGrouprootView=(ViewGroup)content.getChildAt(0)4.ViewRoot控制ViewEvent处理和逻辑处理;ViewRoot子类是ViewRootImpl类,是WindowManagerService和DecorView之间的纽带。View的三大流程(measure、layout、draw)都是通过ViewRoot完成的;ViewRoot不是视图树的一部分。从源码实现来看,它既不是View的子类,也不是ViewGroup的子类,而是实现了ViewParent接口,使其成为View名义上的父视图;RootView继承了Handler类,可以接收事件并进行分发;Android所有的触摸屏事件、按键事件、界面刷新等事件都是通过ViewRoot分发的;二、DecorView创建全过程详解1、attachActivity的setContentView()启动publicvoidsetContentView(@LayoutResintlayoutResID){getWindow().setContentView(layoutResID);initWindowDecorActionBar();}可以看到其实是交给了Window去加载view;finalvoidattach(Contextcontext,ActivityThreadaThread,Instrumentationinstr,IBindertoken,intident,Applicationapplication,Intentintent,ActivityInfoinfo,CharSequencetitle,Activityparent,Stringid,Stringid,NonConfigurationInstanceconfigNastanceslast,Stringreferrer,IVoiceInteractorvoiceInteractor,Windowwindow){................................................................................mWindow=newPhoneWindow(this,window);//创建一个Window对象mWindow.setWindowControllerCallback(this);mWindow.setCallback(this);//设置回调将点击或状态改变等事件分发给ActivitymWindow.setOnWindowDismissedCallback(这个);.........................................................mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),mToken,mComponent.flattenToString(),(info.flags&ActivityInfo.FLAG_HARDWARE_ACCELERATED)!=0);//为Window设置WindowManager对象.........................................................................}在Activity的attach方法中,一个实例生成PhoneWindow;使用Window对象,将DecorView加载到Window中;ADecroViewinstallDecor();}else{mContentParent.removeAllViews();//mContentParent不为空,删除View}mLayoutInflater.inflate(layoutResID,mContentParent);//为mContentParent添加子View,即布局文件集Activity中finalCallbackcb=getCallback();if(cb!=null&&!isDestroyed()){cb.onContentChanged();//回调通知,内容改变}}mContentParent为ContentView对应的FrameLayout;Activity的setContentView的过程大致可以概括为:Activity首先在Attach方法中生成一个PhoneWindow的实例;在setContentView中直接交给Window加载视图,先在PhoneWindow中创建一个DecroVie瓦;在创建过程中,可能会根据Theme加载不同的布局格式,即Activity中设置的布局;3.installDecorprivatevoidinstallDecor(){if(mDecor==null){mDecor=generateDecor();//生成DecorViewmDecor。setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);mDecor.setIsRootNamespace(true);if(!mInvalidatePanelMenuPosted&&mInvalidatePanelMenuFeatures!=0){mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);}}if(mContentParent==null){/DemContentParent==nullentRent)=DemContnull)DecorView设置布局格式,返回mContentParent...}}}protectedDecorViewgenerateDecor(){returnnewDecorView(getContext(),-1);}很简单,创建一个DecorView;lookatgenerateLayout;4、generateLayoutprotectedViewGroupgenerateLayout(DecorViewdecor){//从主题文件中获取样式信息TypedArraya=getWindowStyle();.......if(a.getBoolean(R.styleable.Window_windowNoTitle,false)){requestFeature(FEATURE_NO_TITLE);}elseif(a.getBoolean(R.styleable.Window_windowActionBar,false)){//不允许anactionbarifthereisnotitle.requestFeature(FEATURE_ACTION_BAR);}.........//根据主题样式,加载窗口布局intlayoutResource;intfeatures=getLocalFeatures();//System.out.println("Features:0x"+Integer.toHexString(features));if((features&(1<