一个Activity的显示

来源:互联网 发布:轻松工程测量系统算法 编辑:程序博客网 时间:2024/06/07 03:44

Activity的显示过程主要经历了Activity的Launch和Resume过程,下面针对其显示过程中的一些重要步骤进行分析。

1. ActivityThread - performLaunchActivity

  • 创建PhoneWindow
  • 创建WindowManager
  • setContentView
activity = mInstrumentation.newActivity(...);activity.attach(...);    mWindow = PolicyManager.makeNewWindow(this);    mWindow.setWindowManager(...);        wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);        mWindowManager = new LocalWindowManager(wm); // PhoneWindow的WindowManager是一个LocalWindowManager里面包含一个WindowManagerImpl    mWindowManager = mWindow.getWindowManager(); // activity也保存一份LocalWindowManager mInstrumentation.callActivityOnCreate(activity, r.state);     activity.performCreate(state);         onCreate(state);             setContentView(view);                 getWindow().setContentView(view);                     setContentView(view, params);                         installDecro();                         mContentParent.addView(view, params); // mContentParent即android.R.id.content

2. ActivityThread - handleResumeActivity

  • 创建ViewRoot并获取WindowSession和W类
  • 调用WindowSession.add -> WMS.addWindow,并将W类传给WMS(RPC,SYNC)
  • 调用ViewRoot的requestLayout(ASYNC)
wm = a.getWindowManager(); // 获取activity的LocalWindowManagerwm.addView(decor, l);    mWindowManager.addView(view, params); // 这里才是WindowManagerImpl        root = new ViewRoot(view.getContext);            getWindowSession                // 将IBinder装进一个IWindowManager.Proxy,Proxy也是一个IWindowManager                sWindowSession = IWindowManager.Stub.asInterface(ServiceManager.getService("window")).openSession(...);            mWindow = new W(this, context); // W是在这时创建的        root.setView(view, wparams, panelParentView);            mView = view; // 保存PhoneWindow中的DecorView            requestLayout(); // 最终异步调用到ViewRoot#performTraversals            res = sWindowSession.add(mWindow, ...); // 远程调用WMS的addWindow

对于ViewRoot的理解:
按照平时写布局的直观感觉,认为一个View树的根节点应该是一个ViewGroup,而实现上却是一个ViewRoot,那么这是为什么呢,这个就要看其实现的接口ViewParent的意义了。 ViewParent意为一个View的父节点,那么一个View的父节点理应是ViewGroup啊,其实不然,ViewGroup是一个ViewParent没错,而它本身也是一个View,那么ViewGroup的作用就是要把自己显示出来,并且把自己的子View也显示出来 而ViewRoot只是一个ViewParent,其自身并不是一个View,那么他就负责把子View显示出来,而把忙着要显示自己的精力留出来,处理一些与显示相关的更重要的事情,比如与WMS打交道 这就犹如一个程序员要写代码,项目组长要管理程序员,同时自己也要写代码,而技术总监管理项目组长,自己却不用写代码,把写代码的精力空出来去处理一些更重要的工作

经过上面的步骤,已经为Activity添加了window,并调用requestLayout,进行了显示,接下来就进一步分析Sessionr的添加window和ViewRoot的requelstLayout的过程。

2.1 Session - add

  • 创建WindowState来表示一个Window
  • 创建SurfaceSession与SurfaceFlinger建立连接
  • 将应用端的Binder(即W类)传给WMS,并在mWindowMap中保存W类和WindowState对应关系
WindowManagerService.addWindwow    win = new WindowState(...); // 用来表示一个Window    win.attach();        mSession.windowAddedLocked();            mSurfaceSession = new SurfaceSession(); // 在这里终于与SurfaceFlinger扯上关系了            mNumWindow++;    mWindowMap.put(client.asBinder(), win); // 用map来存储Binder和WindowState的对应关系    return res;

2.2 ViewRoot - requestLayout

relayoutWindow    // 这里的mSurface相当于一个传出参数,接收远程WMS创建的Surface    // 远端通过SurfaceSession创建一个Surface,则该Surface是已绑定一段与显示相关的内存的,往该内存里写数据即可显示在屏幕上    // 远端创建的Surface的mNativeObject是一个SurfaceControl类型,将其通过parcel传送过来,而传到本地后,根据parcel构建出的是一个Surface类型    sWindowSession.relayout(..., mSurface);draw    // 调用上面得到的surface的lockCanvas,可以得到一个绑定了其内存的canvas    // 调用mView(即DecorView)的draw函数,并将canvas传入进去,即可将DecorView及下各层级子view绘制在该canvas所绑定的内存中并显示在屏幕上    Surface surface = mSurface;    canvas = surface.lockCanvas(dirty);    mView.draw(canvas); // mView为DecorView    surface.unlockCanvasAndPost(canvas);

2.2.1 Session - relayout

  • 在服务端创建Surface,并传回给应用端
WindowManagerService.relayoutWindow    Surface surface = win.createSurfaceLocked(); // win为addWindow时创建的WindowState        mSurface = new Surface(mSession.mSurfaceSession, ...);    outSurface.copyFrom(surface); // 将Service端创建的surface传给Client端

2.2.2 Surface - lockCanvas

  • 从Surface中获取SurfaceInfo,其包含绑定的内存,将该内存绑定到一个bitmap并赋给canvas
lockCanvasNative -> Surface_lockCanvas    // 这里先取出Native的Surface    const sp<Surface>& surface(getSurface(env, clazz));    // 调用native的surface的lock并获取SurfaceInfo    Surface::SurfaceInfo info;    status_t err = surface->lock(&info, &dirtyRegion);    // 获取canvas和nativeCanvas    jobject canvas = env->GetObjectField(clazz, so.canvas);    SkCanvas* nativeCanvas = (SkCanvas*) env.GetIntField(canvas, no.native_canvas);    // 设置format,width,height,size和内存    bitmap.setConfig(...);    bit.setPixels(info.bits);    // 给canvas设置bitmap;    nativeCanvas.setBitmapDevice(bitmap);

2.3 ViewRoot和WMS关系

这里写图片描述
ViewRoot通过 IWindowManager.Stub.asInterface(ServiceManager.getService("window")) 获得一个IWindowManager,然后通过其openSession获得一个IWindowSession
ViewRoot通过IWindowSession远程调用WMS
WMS通过IWindow远程调用ViewRoot中的W对象

Created with Raphaël 2.1.0WindowManagerImplWindowManagerImplViewRootViewRootWindowManagerServiceWindowManagerServiceSessionSessionnew ViewRoot()new Surface()openSession()new Session()add()new SurfaceSession()relayout()relayoutWindow()Surface surface = win.createSurfaceLocked();outSurface.copyFrom(surface);

(待续)

3. 画图四大组件

  • Bitmap
  • Canvas
  • Drawing primitive
  • Paint

4. FrameBuffer

图像数据的传输过程是:

  • 由客户端把数据写到共享内存中
  • 然后由SurfaceFlinger从共享内存中取出数据再往硬件发送

承载图像数据的就是FrameBuffer(简称FB)

FrameBuffer的中文名叫缓冲帧,它实际上包含两方面:

  • Frame:帧,指一幅图像,即屏幕上的一帧。
  • Buffer:缓冲,就是一段内存,用来存储帧数据。

FrameBuffer中的Buffer,是通过mmap系统调用把显示设备中的显存映射到用户空间,在这块缓冲区上写数据,就相当于在屏幕上绘画。

Linux FrameBuffer(简称LFB),是Linux平台提供的一种可直接操作FB的机制,依托这个机制,应用层通过标准的系统调用,就可以直接操作显示设备了。

0 0
原创粉丝点击