一个Android Activity的显示

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的LocalWindowManager
wm.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对象

WindowManagerImpl ViewRoot WindowManagerService Session new ViewRoot() new Surface() openSession() new Session() add() new SurfaceSession() relayout() relayoutWindow() Surface surface = win.createSurfaceLocked() outSurface.copyFrom(surface) WindowManagerImpl ViewRoot WindowManagerService Session

(待续)

3. 画图四大组件

  • Bitmap
  • Canvas
  • Drawing primitive
  • Paint

4. FrameBuffer

图像数据的传输过程是:

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

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

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

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值