以上是WMS端視窗的添加,下面接着ViewTree周遊中最後一步的Draw的分析。
private boolean drawSoftware()à canvas =mSurface.lockCanvas(dirty);
跟View互動的是Canvas,比如draw(Canvas cs)參數,應用程序與surfaceflinger互動的是surface,即應用程序端的本地視窗,那麼canvas和surface之間怎麼協作的?
lockCanvas @Surface.java –>nativeLockCanvas@ android_view_Surface.cpp
static jlong nativeLockCanvas((){
//這個是C++層的surface對象
sp<Surface>surface(reinterpret_cast<Surface *>(nativeObject));
//擷取一個存儲UI資料的buffer,
ANativeWindow_BufferoutBuffer;
//通過IGraphicBufferProducer的dequeuBuffer,擷取一個可用的buffer,
status_t err =surface->lock(&outBuffer, dirtyRectPtr);
//為bitmap配置設定記憶體空間,為bitmap配置設定可用的存儲空間
SkBitmapbitmap;
bitmap.setInfo(info,bpr);
bitmap.setPixels(outBuffer.bits);
//構造本地層的canvas,第二個參數是canvasObj是java層的canvas對象
Canvas*nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
//給canvas這個作畫的工具集設定作畫的畫紙,也就是bitmap,實際上bitmap的畫紙來自于outBuffer,而outBuffer所指向的記憶體是surface通過lock去申請
nativeCanvas->setBitmap(bitmap);
//傳回一個java層的surface
sp<Surface>lockedSurface(surface);
return (jlong)lockedSurface.get();
}
typedef struct ANativeWindow_Buffer {
// The number of pixels that are show horizontally.
int32_t width;
// The number of pixels that are shown vertically.
int32_t height;
// The number of *pixels* that a line in the buffer takes in
// memory. This may be >=width.
int32_t stride;
// The format of the buffer. Oneof WINDOW_FORMAT_*
int32_t format;
// The actual bits.
void* bits;
// Do not touch.
uint32_t reserved[6];
} ANativeWindow_Buffer;
ANativeWindow_Buffer中的屬性void*bits就是canvas中作畫,存儲資料的地方。
Surface的職責隻是管理SurfaceFlinger配置設定的用于存儲UI資料的記憶體塊,它是一個中介,通過與SurfaceFlinger的協作滿足上層的需求。
status_t Surface::lock(){
// 目前是否有buffer被locked,因為被Locked的buffer隻能有一個,以mLockedBuffer表示
if(mLockedBuffer != 0)
// 執行連接配接到CPU
interr = Surface::connect(NATIVE_WINDOW_API_CPU);
//設定記憶體塊的用法,
setUsage(GRALLOC_USAGE_SW_READ_OFTEN| GRALLOC_USAGE_SW_WRITE_OFTEN);
//dequeue一個可用的buffer,是通過GraphicBufferProducer來向BufferQueue擷取一個buffer,這裡有frontBuffer,backBuffer分别代表上一次處理的buffer和目前正在處理的buffer,兩次圖像更新間通常不需要重繪整個區域,可以借助之前的buffer填充本次的buffer内容,判斷是否可以從上一次的buffer中copy資料的依據就是buffer的寬、高、格式是否一緻。不能copy就要重繪整個界面。
status_terr = dequeueBuffer(&out, &fenceFd);
//鎖定buffer
status_tres = backBuffer->lockAsync()
}
status_t Surface::unlockAndPost(){
//UI繪制完成,需要解鎖,Buffer入隊,送出給SurfaceFlinger渲染,SurfaceFlinger後續會這一buffer進行處理,最終顯示到螢幕上
status_terr = mLockedBuffer->unlockAsync(&fd);
err= queueBuffer(mLockedBuffer.get(), fd);
}
分析了native層canvas的實作機制,回到java層的performDraw
drawSoftware()@ViewRootImpl.javaà mView.draw(canvas);//同樣從viewtree根元素開始
public void draw(){
//從View樹的根元素開始,逐漸往下繪制
mView.draw(canvas);
}
public void draw(Canvas canvas) {
//繪制背景,要考慮是否進行坐标變換
drawBackground(canvas);
//繪制内容,調用具體子類的onDraw方法
if(!dirtyOpaque) onDraw(canvas);
//遞歸繪制子對象,調用ViewGroup子類的實作
dispatchDraw(canvas);
//畫scrollbar
onDrawScrollIndicators(canvas);
onDrawScrollBars(canvas);
}
onDraw就是具體的繪制,以ImageView為例
[email protected]{
//把drawable中内容繪制到這個canvas上
mDrawable.draw(canvas);
}
上面應用程序寫完内容後,會解鎖這個buffer并queueBuffer,把資料送出:
[email protected]>[email protected]
在把這個buffer入隊,即queuebuffer時,[email protected]這個方法中,會通過sp<IConsumerListener>frameAvailableListener這個監聽,把目前有可消費的buffer的這個事件通過onFrameAvailable發出去,這樣buffer的消費者就會取這個buffer。