編輯:Android開發實例
應用程序中不同類型的Surface,在FrameWorks本地層的SurfaceFlinger中,分別對應著不同的Layer類,本文主要是討論這幾種Layer的實現和差異。
閱讀本文之前,最好對SurfaceFlinger這個系統服務有所了解,可以參閱我的以下兩篇文章:
下面幾張圖片分別表示了不同Layer產生的視覺效果:
默認地,創建普通的窗口Surface,在SurfaceFlinger中會創建Layer類,如果想創建LayerDim或LayerBlur,應用程序需要在綁定View之前設置一下窗口的標志位:
創建LayerDim效果:
- @Override
- protected void onCreate(Bundle icicle) {
- // Be sure to call the super class.
- super.onCreate(icicle);
- // Have the system blur any windows behind this one.
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
- WindowManager.LayoutParams.FLAG_DIM_BEHIND);
- ......
- setContentView(......);
- }
創建LayerBlur效果:
- @Override
- protected void onCreate(Bundle icicle) {
- // Be sure to call the super class.
- super.onCreate(icicle);
- // Have the system blur any windows behind this one.
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
- ......
- setContentView(......);
- }
相應地,在SufaceFlinger中,會根據Java層傳入的標志,創建不同的Layer:
- sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
- const String8& name, ISurfaceFlingerClient::surface_data_t* params,
- DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
- uint32_t flags)
- {
- sp<LayerBaseClient> layer;
- sp<LayerBaseClient::Surface> surfaceHandle;
- ......
- switch (flags & eFXSurfaceMask) {
- case eFXSurfaceNormal:
- if (UNLIKELY(flags & ePushBuffers)) {
- layer = createPushBuffersSurfaceLocked(client, d, id,
- w, h, flags);
- } else {
- layer = createNormalSurfaceLocked(client, d, id,
- w, h, flags, format);
- }
- break;
- case eFXSurfaceBlur:
- layer = createBlurSurfaceLocked(client, d, id, w, h, flags);
- break;
- case eFXSurfaceDim:
- layer = createDimSurfaceLocked(client, d, id, w, h, flags);
- break;
- }
- if (layer != 0) {
- layer->setName(name);
- setTransactionFlags(eTransactionNeeded);
- surfaceHandle = layer->getSurface();
- ........
- }
- return surfaceHandle;
- }
下面的圖展示了Layer類之間的繼承關系:
ISurface接口其實非常簡單,只有幾個函數:
LayerBaseClient的派生類中,會有一個內嵌類,繼承LayerBaseClient::Surface,然後根據需要會實現該接口的相應函數。
Layer類是使用最多的一個,普通的應用程序窗口都會對應一個Layer類,Layer類的內嵌類SurfaceLayer繼承了ISurface接口,創建Layer類時,將會返回一個ISurface接口給創建者。並且,Layer類在創建時會建立兩個GraphicBuffer對象,這兩個Buffer在不同的時刻分別被作為frontbuffer和backbuffer,frontbuffer用於本窗口的畫圖操作,backbuffer用於所有窗口的混合操作。但是兩個GraphicBuffer對象在創建時並沒有真正地分配內存,而是在第一次lockBuffer時才正式通過ISurface接口的requestBuffer方法申請內存,當窗口的大小發生變化時,也要重新分配適合窗口大小的內存。Layer類的主要成員函數如下:
LayerDim和LayerBlur,他們的顯示內容是固定不變的(透明的黑色),所以不需要分配兩個GraphicBuffer對象,因此它們也沒有繼承自LayerBaseClient::Surface的內嵌類,而是直接使用LayerBaseClient::Surface類作為它們的ISurface接口。以LayerDim為例跟蹤一下它的Draw過程:
- void LayerDim::initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h)
- {
- sTexId = -1;
- sImage = EGL_NO_IMAGE_KHR;
- ......
- if (LIKELY(flags & DisplayHardware::DIRECT_TEXTURE)) {
- /* 申請GraphicBuffer */
- sp<GraphicBuffer> buffer = new GraphicBuffer(w, h, PIXEL_FORMAT_RGB_565,
- GraphicBuffer::USAGE_SW_WRITE_OFTEN |
- GraphicBuffer::USAGE_HW_TEXTURE);
- android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
- /* 申請OpenGL貼圖 */
- glGenTextures(1, &sTexId);
- glBindTexture(GL_TEXTURE_2D, sTexId);
- EGLDisplay dpy = eglGetCurrentDisplay();
- sImage = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)clientBuf, 0);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)sImage);
- ......
- // initialize the texture with zeros
- GGLSurface t;
- buffer->lock(&t, GRALLOC_USAGE_SW_WRITE_OFTEN);
- memset(t.data, 0, t.stride * t.height * 2);
- buffer->unlock();
- sUseTexture = true;
- }
- }
- void LayerDim::onDraw(const Region& clip) const
- {
- const State& s(drawingState());
- Region::const_iterator it = clip.begin();
- Region::const_iterator const end = clip.end();
- if (s.alpha>0 && (it != end)) {
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- ......
- /* 設置透明值 */
- glColor4x(0, 0, 0, alpha);
- #if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
- if (sUseTexture) {
- glBindTexture(GL_TEXTURE_2D, sTexId);
- glEnable(GL_TEXTURE_2D);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- const GLshort texCoords[4][2] = {
- { 0, 0 },
- { 0, 1 },
- { 1, 1 },
- { 1, 0 }
- };
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(2, GL_SHORT, 0, texCoords);
- } else
- #endif
- {
- glDisable(GL_TEXTURE_2D);
- }
- GLshort w = sWidth;
- GLshort h = sHeight;
- const GLshort vertices[4][2] = {
- { 0, 0 },
- { 0, h },
- { w, h },
- { w, 0 }
- };
- glVertexPointer(2, GL_SHORT, 0, vertices);
- while (it != end) {
- const Rect& r = *it++;
- const GLint sy = fbHeight - (r.top + r.height());
- glScissor(r.left, sy, r.width(), r.height());
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- }
- }
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- }
《未完待續》
可以顯示在的Android任務,通過加載進度條的進展。進度條有兩種形狀。加載欄和加載微調(spinner)。在本章中,我們將討論微調(spinner)。Spinner 用
Android提供了許多方法來控制播放的音頻/視頻文件和流。其中該方法是通過一類稱為MediaPlayer。Android是提供MediaPlayer類訪問內置的媒體播放
本文實例講述了Android編程學習之異步加載圖片的方法。分享給大家供大家參考,具體如下: 最近在android開發中碰到比較棘手的問題,就是加載圖片內存溢出。我
引言 程序猿們,是否還在為你的老板辛辛苦苦的打工而拿著微薄的薪水呢,還是不知道如何用自己的應用或游戲來賺錢呢! 在這裡IQuick將教您如何同過自己的應用