天天看點

App的啟動過程(5)ViewTree周遊中最後一步的Draw

以上是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。

繼續閱讀