第八章 Android GWES
8.1 View System
View & ViewGroup
Android的 UI系统是建立在View和ViewGroup之上的。View是组成UI基本部件,而ViewGroup可以把它看做Panel,就是容器。可以把 View和ViewGroup放到一个ViewGroup里布局,这些View和ViewGroup就组成了显示UI的树形结构(下图)。 Activity创建的Window中的主View既DecorView继承自FrameLayout,而FrameLayout又继承自 ViewGroup,这个DecorView就是每个Activity最最根部的那个ViewGroup。
View在Android中不单纯只是 负责显示功能,它还封装了UI Event的处理功能。在系统中所有要显示的UI元素都继承自View(Surface除外),用户可以使用Android中已实现的一些View的子 类,这些子类包括TextView,Button等,在这里叫他们widget,这些widget都继承自View,但都他们各自的UI表现形式,以及对 UI Event的不同处理方式。当然如果用户觉得这些widget无法满足的话,可以自定义View,既用户去实现一个继承了View的类,也可以继承 widget,并对View的相关成员函数进行重写,如OnDraw。
UI Event
View中以接口的形式定义一些类UI Event处理,其实接口里就是定义了一个回调函数,共使用者去实现,当有消息来时,就会调用到使用者实现的回调函数里。
参 考View.java public void setOnTouchListener(OnTouchListener l) { mOnTouchListener = l; } public interface OnTouchListener { boolean onTouch(View v, MotionEvent event); }
public boolean dispatchTouchEvent(MotionEvent event) { if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)) { return true; } return onTouchEvent(event); }
参考usr.java usrTouchView. setOnTouchListener(new OnTouchListener{ onTouch() { TODO:: } })
关于消息是如何传递到dispatchTouchEvent的,在输入消息处理那一块会有详细介绍。
Graphics
上 面介绍了View是如何处理UI Event,接下来会介绍View是如何显示出来,既画出来的。前面提到过View的OnDraw函数,可以说View的所有显示都在OnDraw里面, 每当View需要刷新时,都会调用的OnDraw,它的函数声明如下: protected void onDraw(Canvas canvas)
每 一个View的子类,包括widget都对它重写,这个函数的重点就是Canvas,所有显示的画图动作都是通过该类来实现的。它位于 android.Graphics的package内,Canvas提供一些类画图的方法,如drawPath(Path path, Paint paint)。使用Canvas画图还需要一些其他资源
 Bitmap:用于承载pixel,既所画的内容
 Path:Region提供画的区域
 Paint:描述颜色及样式
参 考Canvas.java public void drawPath(Path path, Paint paint) { native_drawPath(mNativeCanvas, path.ni(), paint.mNativePaint); }; private static native void native_drawPath(int nativeCanvas, int path, int paint);
从上面的代码片段了解到Canvs的这些画图方法,最后都是调用相对应的native API。这些native API到底层的调用流程是Skia/OpenGL====>SurfaceFlinger=====>framebuffer。
8.2 Android窗口管理
Activity如何启动的?
系 统初始化时会启动一系列服务,这其中包括Activity Manager Service和Window Manager service,这些Service属于常驻程序,应用的进程可获得Service的本地代理来与Service进行通信,一般通过Binder或 AIDL接口。
Activity启动首先要程序的进程跑起来,而一个应用程序的主线程的启动时通过AMS(Activity Manager Service的缩写)创建Activity Thread对象,并由该对象来创建进程的主线程,通过AMS的request调度该进程的Activity。并且会创建消息循环Looper来实现消息 的分发。
下图是介绍ActivityThread中的ActivityRecord与AMS中HistoryRecord联系。
ActivityThread 的成员变量mActivities是个数组,用来保存该进程中的所有的Activity,并以ActivityRecord形式存在,而在AMS中也同样 有个mHistory数组来管理所有的Activity。这个mHistory保存的是HistoryRecord类,HistoryRecord中有 token,taskid。Taskid标示是哪个task, token标示哪个Activity。
Activity启动流程
1. 发起请求startActivity(intent)
2. Activity Service Manager接收到请求执行StartActivity函数。
3. 通过app.thread.scheduleLaunchActvity在App应用中建立新的ActivityRecord。
4. 建立新的Activity对象并放入到ActivityRecord中。
5. 将ActivityRecord加入到mActivites@ActivityThread
6. 发起Activity.onCreate(..),,该onCreate就是在你的应用程序XXXActivity中的onCreate。
窗口的基本框架
Activity建立一个主窗口后,在将主窗口添加到WindowManager时,首先要建立
WindowManager 代理对象,并打开一个会话(实现IWindowSession AIDL接口),并维持该会话。Activity将通过该会话与WindowManager建立联系,这个Session是C/S体系的基 础,Client通过WindowSession将window加入到Window Manager中。客户端的Activity通过Session会话与WindowManager建立对话,而WindowManager则通过 IWindow接口访问Client,将消息传递到Client端,通过消息分发渠道,将消息传递到处理函数OnXXX。
在 ActivityThread调用performLaunchActivity时,会使用Activity.attach()建立一个 PhoneWindow主窗口。这个主窗口的建立并不是一个重点。当ActivityThread调用handleResumeActivity去真正启 动一个Activity时候,将主窗口加入到WindowManager,当然并不是将主窗口本身,而是将主窗口的DecorView加入到 WindowManager中。DecorView实际上是一个ViewGroup,DecorView是Top-Level View。
下图描述的是如何将窗口的主View既DecorView添加到window manager
图 中在添加DecorView到WM中时,会创建一个ViewRoot,每个窗口(DecorView)都会对应一个ViewRoot,他是整个View树 形结构的根,ViewRoot实际是一个Handler,View Tree消息的发送和处理都是从他开始。ViewRoot是建立主View与WindowsManger通讯的桥梁。ViewRoot与Window Manager之间的联系是IWindowSession和IWindow。ViewRoot通过IWindowSession添加窗口到Window Manager。而IWindow这是Window Manager分发消息
给Client ViewRoot的渠道。IWindowSession和IWindow都是AIDL接口,窗口与Window Manager Service就是利用这两个AIDL接口进行进程间通信。
消息机制Looper,Handle,MessageQueue
Looper只是产生一个消息循环框架,首先Looper创建了MessageQueue并把它挂接在Linux的线程上下文中,进入到取消息,并分发消息的循环当中。
Handle对象在同一个线程上下文中取得MessageQueue,最主要的就是SendMessage和担当起dispatchMessage这个实际工作。
MessageQueue就是消息队列,用来存放消息。
消 息的产生及处理流程(见上图),首先在应用程序启动时会创建ActivityThread对象来启动主线程,并管理当前应用所有的Activity,保存 到mActivities数组中(详细介绍见Activity启动介绍),在ActivityThread里会创建一个Looper对象,既该线程的所有 Activity都共用一个消息循环,Looper里会创建MessageQueue来存放Msg,Looper对象创建成功后,会调用Looper的静 态成员函数loop()开始消息循环,该静态函数中会获得当前线程的Looper对象,并从该Looper的MessageQueue中 GetMessage,获得的msg对象有个target的成员变量,该target就是要处理该msg的Handle对象,如果target为 null,则代表终止该消息循环,否则调用该handle的dispatchmessage,该函数中会调用handlemessage回调函数,该函数 会对消息进行处理,每个创建的handle对象要对handlemessage进行重写。如ViewRoot的handlemessage就是分发到 Focus View的OnXXX()。
但是消息是如何放到MessageQueue中的呢?下面介绍一下Handle类,就是刚才提到的msg 中的target域,该类中包括handlemessage,dispatchmessage以及一系列sendmessage函数,前两个函数的应用场 景前面已经讲过了。这一系列SendMessage就是最后都会调用sendMessageAtTime(),这个函数就是把发送的消息放到当前消息循环 的MessageQueue中。
对输入事件如何响应?
系统中与用户交互的程序,都是用户使用输入设备(鼠标,键盘,触控板),然后由这些 设备的驱动获得输入,并生成Event,放到Event队列中。上层的Window Manager Service会通过Native函数来读取这些Event,并分发到具体的Focus View上。
1、 输入事件的收集
WindowMangerService 启动时会创建一个KeyQ对象mQueue,这是一个消息队列,继承自抽象类KeyInputQ,在KeyInputQ中建立一个独立的线程 InputDeviceReader,使用Native函数readEvent来读取Linux Driver的数据构建Raw Event,放到KeyQ消息队列中。
2、 消息分发到Focus Window
WMS(Window Manager Service)有InputDispatcherThread的线程,该线程循环的从mQueue中获得Raw Events,并根据Event Type分别调用不通dispatch函数(dispatchKey, dispatchPointer, dispatchTrackball),在WMS的dispatch找到中的Focus Window,下面的代码片段中WindowState,是Client端Window在WMS端的对应对象,通过WindowState记录的 mClient(IWindow)接口,将Events专递到Client端。 //InputDispatcherThread DispatchKey() { Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null, null, false, false, pid, uid); 。。。 WindowState focus = (WindowState)focusObj; 。。。 Focusobj.mClient.dispatchKey(event) 。。。 }
3、 应用消息队列分发
通过上面窗口的框架介绍, 我们了解到WindowState中mClient既IWindow接口,是WMS同Activity的Window沟通的接口,通过该接口把event 发到Focus Window的ViewRoot对象,ViewRoot继承自Handle,ViewRoot中的dispatchKey会调用SendMessage, 把该Event发到当前线程的消息队列里,最后会调用到ViewRoot重写handlemessage。
4、 通过FocusPath,发到FocusView
ViewRoot的handlemessage函数找到他对应DecorView并,按下图所示的Focus Path会最终传递到要处理该事件的view上,并调用相应的回调处理函数,如OnClick()。

转自:http://blog.csdn.net/googleandroider/article/details/6580929

更多相关文章

  1. 箭头函数的基础使用
  2. Python技巧匿名函数、回调函数和高阶函数
  3. Android横竖屏切换方法
  4. Android(安卓)MediaPlayer的核心原理
  5. Android和js、H5进行交互数据
  6. Android调用Java端,Android于Java后台交互,Android如何导入外部jar
  7. 从源码的角度分析Handler
  8. Flutter——在Android平台上的启动流程浅析
  9. Android(安卓)JNI开发入门之一

随机推荐

  1. Android(安卓)代码混淆
  2. android 加载图片轻松避免OOM(out of mem
  3. Android(安卓)AsyncChannel源码分析
  4. Android(安卓)IO
  5. Android(安卓)开发者(Android(安卓)Develo
  6. Android中使用Dialog风格弹出框的Activit
  7. Android(安卓)TextView设置个别字体样式
  8. Android联机开发Python
  9. ADB命令大全
  10. Android属性(android:gravity)的说明