Android GUI系统 View体系 深入理解Android内核思想 第十一章 笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012654756/article/details/89350023

第十一章 GUI系统-View体系

前面分析了ANDROIDGUI系统底层支撑框架,SF和WMS两个系统服务的内部原理。

但是从用户角度,他们不关心。

真正与用户联系的,是View体系,。所有APK应用程序的UI界面都是它描述的。

这里有个AP进程里面的View框架图

Activity是API各个组件中使用率最高的 ,专门设计用于UI界面的显示和处理。

当然其他组件也可以显示UI,但是要多很多额外工作。

对于AP开发,他们用SDK向导生成一个带Activity的AP模板,根据需求 加工ANdroid提供的半成品:

setContentView, onCreate, onStart等方法,快速定制AP。;

从系统实现角度,ANdroid为了提供便捷的半成品,做了很多努力。

讲代码前,有下面几个问题,是很多开发者疑惑的:

View和ViewRoot

以xml描述UI界面的layout,可以发现里面所有元素实际都是树状结构:

<LinearLayout xmlns:..... android:id="@+id/top"..> <LinearLayout android:id="@+id/digits_conteiner"..> <com.android.conteacts.dialpad.DigitsEditTText android:id="@+id/digits".../> <ImageButton android:id="@+id/deleteButton".../> </LinearLayout> <View android:id"@+id/viewEle".../> </LinearLayout>

树形表示:

top

digits_container ViewEle

digits deleteButtion

ViewRoot看起来像是View树的根,但是是误解。

ViewRoot不是View树的一份子。ViewRoot和View对象没有任何血缘关系。

它不是View的子类,也不是父类。ViewRoot可以理解为View树的管理者:

它有一个mView成员变量,指向的是它管理的View树的根,就是图中id为top的元素。

ViewRoot的核心任务是与WindowMnagerService通信,后面说。

★Activity和Window的关系

Activity是支持UI显示的,它是否直接管理View数或者ViewRoot呢?不是。

Activity和他们没有直接联系,中间还有一个被称为Window的对象。

具体说,Acitivity内部有一个mWindow变量:

private Window mWindow;

window就是窗口。Window是基类,根据不同产品衍生不同子类,具体是由系统在Activity.attach中调用PolicyManager.makeNewWindow决定,目前Android系统默认生成的都是phoneWindow。

★,Window与WindowManagerImpl的管理

Window开头的类很多:Window,WindowManager,WindowManagerImpl,为什么那么多相似的类?

先看WIndow,它是面向Activity的,表示UI界面的外框;

框里面包括布局和内容,是由具体的Window子类,如PhoneWIndow去规划的。

但无论最终生成的窗口怎么样,Activity不用修改。

Window的另一层含义是要和WindowManagerService通信,它没有直接在自身实现这个功能。

原因是一个AP可能有多个window,如果都单独与WMS通信,那浪费资源,且管理混乱。所以要统一管理。

就有了WindowManager,

它作为Window的成员变量mWindowManager存在。

WindowManager是一个接口类,真正的实现是WindowManagerImpl,后者同时也是整个AP所有Window的管理者。

所以WindowManager与WindowManagerImpl的关系像是地方与中央。

地方为了实施中央的政策,提供了一个接口,然后汇总给中央进行管理。

★,ViewRoot和WindowManagerImpl的关系

早期系统,WIndowMangerImpl在每个进程只有一个实例。要调用它必须用:WindowManagerImpl.getDefault();

WindowManagerImpl内部,有3个全局变量:

private View[] mViews; private ViewRootImpl[] mRoots; private WindowManger.LayoutParams[] mParams

分别表示View书的根节点,ViewRoot以及Window的属性。

可以看出,一个进程不仅仅有一个ViewRoot,Activity与ViewRoot则是一一对应的关系。

Andorid4.3修改了,WindowManagerImpl不在直接存储那3个数组变量,而是有一个称谓WinndowManagerGlbal的类去统一管理。

另外,还对各个类的关系进程了梳理,提出了一些历史遗留的无关类。

当然,统一管理ViewRoot和View数的本质,是没有变的,换汤不换药。

每一个ViewRootImpl内部,有一个全局变量:

static IWindowSession sWindowSession;

它用于VewiROot到WMS的连接,是ViewROot利用WMS的openSession()接口创建得到得分。

在此基础上,ViewRoot也会通过IWindowSession.add()方法提供一个IWindow对象----从而让WMS也可以通过这个Binder对象来与ViewRoot进行双向通信。

类之间的关系:

这里有个图,很很重要

图11-3 Activity,WindowManagerGlobal,WMS的关系图

每个APP都有一个ActivityThread主线程和mActivities全局变量,后者记录了运行在AP中的所有Activity对象。

一个Activity对应唯一的WindowManager和ViewRootImpl。

WindowManagerGlbal作为全局管理者,内部的mRoots和mViews记录了各个Activity的ViewRootImpl和View数的顶层元素。

ViewRootImpl的另一个重要角色就是负责与WMS通信,从ViewRootImpl到WMS间的通信利用的是IWindowSession,反方向由IWindow完成。

11.2 Activity中ViewTree的创建过程

Actrivity与其他组件的最大的不同,就是它内部拥有完整的界面显示机制,

其中涉及ViewRootImpl,Window和又他们管理的View Tree等,

下面详细说ViewTree,

这里有个流程图:

参与ViewTree创建的有几个主体:ActivityThread, Activity, PhoneWIndow, ViewRootImpl, WM(本地的WM or 服务端WMS,不严格区分先)

流程:

1,作为AP的主线程,ActivityThread负责处理各种核心事件,如AMS通知AP进启动一个Activity,这个任务,最终会转化为ActivitThread管理的LAUNCH_ACTIVITY消息, 然后调用handleLaunchActivity(),这是整个VewiTree建立流程的起点。

2,handleLaunchActivity()内部,细分为两个过程:

→performLaunchActivity;

→handleResumeActivity,(注意Resume的处理时机有多种情况,我们以此为例)

代码:

//frameworks/base/core/java/anroid/.app/ActivityTHrad.java private void handleLaunchActivity(ActivityClientRecoed r, Intent customIntent){ Activity a = performLaunchActivity(r, customIntent) //启动Activity if(a != null){ handleResumeActivityu(r.token, false, r.isForward) //Resume这个Activity }.. }..

下面结合本节开头的序列图,分析这两个函数。

1,performLaunchActivity

private Activity performLaunchActivity(ActivitryClientRecoed r, Intent customnIntent){ ... Activity activity = null; try{ java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); //类加载器 activtiy = mInstrumentation.newActivity(cl, component.getClassName(), r.initen);//加载这个Activity对象。 ... }catch(Exception e){} try{ Application app = r.packageInfo.,makeApplication(false, mInstrumentation); ... if(Activity != null){ .. activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.actrivietyInfo, title, r.parent, r.embeddedID, r.laseNonConfigurationInstances, Config); .... mInstrumentation.callActivityOnCrteate(activity, r.state) //最终会调用Activity.onoCreate() } }catch(SuperNotCalledException e){} }

这个函数主要任务是生成一个Activity对象,然后调用它的attach方法,再通过Instrumentation.callActivityOnCreate间接调用Activity.OnCrreate。

其中attach将为Activity内部众多的全局变量赋值,最重要的就是mWIndow:

mWindow = PolicyManager.makeNewWIndow(this);

这里得到的就是一个PhoneWIndow对象,它在每个Activity中有且仅有一个实例。

WIndow在Acitivity中可以看成界面的框架抽象。

所以有一个Window后,还要生成具体的View内容,就是Activity中的mDecor。

Decor就是装饰,就是说它出列包括Acitivy实际要显示的内容外还要具备所有AP共同的装饰部分。比如Title,ActionBar(是否要显示装饰取决于AP的需求)

产生DecorView的过程是由SsetContentView发起的,也就是开发者需要在onCreate的时候调用这个函数的原因。

而onCreate本身则是由mInstrumentation.callAcitvityOnCreate(activity, r.state)间接调用的。有兴趣自行分析。

Activity的setContentCView只是一个中介,它将通过对应的Window对象完成DecorView的构造:

//frameworks/base/policy/src/com/andorid/internal/policy/impl/PhoneWindow.java public void setContentView(int layoutResID){ if(mContentParent == null) { //如果是第一次调用这个函数 installDecor();//首先要生成mDecor对象 }else{ mContentParent.removaAllViews(); //不是第一次调用,移除旧的 } mLayoutInflater.inflate(layoutResID, mContentParent); //根据ResId创建View对象 }

mContentParen是一个ViewGroupsp对象,它用于容纳ContentView,

当mContentParent是空,说明是第一次调用setContentView。

此时mDecor也一定是空的,所以调用installDecor创建一个DecorView;

否则先清理mContentParent中已有的所有View对象 。

最后通过layoutResID来inflate新的内容,mContentParent即使这个由LaytouResID生成的View树的根。

可以看出,setContentCiew可以被AP多次调用,但一般不这么做。

函数installDecor由两个任务,,生成mDecor和mContentParent。

private void installDecor(){ if(mDecor == null){ mDecor = generateDecor(); } }

函数generateDecor实际只是new一个DecorView对象,返回值赋予mDecor。

DecorView继承自FrameLayout,后面分析原因。

mContentParent的创建过程与mDecor有关联,代码:

if(mContentParent == null){ mContentParent = generateLayout(mDecor); }//installDecor结束

可以看到,mCOntentParent通过generateLayout函数生成,

protected ViewGroup generateLayout(DecorView decor){ TypedAttay a = getWindowStyle(); //获取窗口样式 mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false); ... int layoutResource; int features = getLocalFeatures(); if((features & ((1<<FEATURE_LEFT_ICON)| (1<<FREATURE_RIGHT_ICON))!= 0)){ //根据具体的样式为layoutResource挑选匹配的资源 }else if(features&(1<<FEATRURE_PROGRESS)|(1<<FEATURE_INDETERMINATE_PROGRESS)...){ }else if(features & (1<<FEATURE_CUSTOM_TITLE)!= 0){ }else if (...FEATURE_ACTION_MODE_OVERLAY...){} View in = mLayouInflater.inflate(layoutResource, null) //将资源inflate出来 decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); ViewGoup contentParent = (ViewGroup)findViewByID(ID_ANDROID_CONTENT); ... return contentParent; }

framework提供的这些默认layout文件统一放在frameworks/base./core/res/res/.layout里面

根据layoutResource指定的layout(xml)文件,来inflate出相应的View对象。

然后把这个新对象addView到mDecor,DecorView是一个FrameLayout。

最后,整个generateLayout哈数返回值是一个id为ID_ANDOIRD_CONTENT=con.andoier.internal.R.id.content的对象,也就是mContentParent。

图:DecorView的layout之一

所以,setConteentView实际就是把AP想要显示的视图ContentView加上系统策略的其他元素,如title,action,

合成出用户看到的接种AP的界面,如图。

注意setContentView不负责显示,可以实验,在Activity中不调用setContentView,AP的界面还是可以显示,只是中间的content是空的,。

然后列举了AP常用的Menu

2,handleResumeActivity

猜你喜欢

转载自blog.csdn.net/u012654756/article/details/89350023