天天看點

05 Gallery 源碼-AlbumSetPaged的界面渲染

0. 原文拜讀

https://blog.csdn.net/lb377463323/article/details/70275971

1. AlbumSetPage界面資料裝載和界面重新整理,為界面渲染作準備

1. 資料裝載

package com.android.gallery3d.app;

public class AlbumSetPage extends ActivityState implements OnClickListener,...{
    
    private AlbumSetDataLoader mAlbumSetDataAdapter;
    
    @Override
    public void onResume() {
        super.onResume();
        ...
        mAlbumSetDataAdapter.resume();
        ...
    }
    
}

           
  • 上接mAlbumSetDataAdapter.resume()
package com.android.gallery3d.app;

public class AlbumSetDataLoader {

    public void resume() {
        mSource.addContentListener(mSourceListener);
        mReloadTask = new ReloadTask();
        mReloadTask.start();
    }
           
  • 上接 ReloadTask()
// TODO: load active range first
    private class ReloadTask extends Thread {
        @Override
        public void run() {
            while (mActive) {
                ...
                // 資料加載完成,進入界面重新整理
                executeAndWait(new UpdateContent(info));
            }
        }
        
    }
           

1.2 界面重新整理的回調事件

  • 上接 executeAndWait(new UpdateContent(info));
private class UpdateContent implements Callable<Void> {
        private final UpdateInfo mUpdateInfo;

        @Override
        public Void call() {
            ...
            for (DataListener l : mDataListener) {
                l.onSizeChanged(mSize);
            }
            ...
            
            for (DataListener l : mDataListener) {
                l.onContentChanged(info.index);
            }
        }
    }
           
  • 檢視下接口定義
package com.android.gallery3d.app;

    public static interface DataListener {
        public void onContentChanged(int index);
        public void onSizeChanged(int size);
    }
           
  • grep指令檢視實作該接口

    目前隻有 AlbumSetSlidingWindow 實作

src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java:40:public class AlbumSetSlidingWindow implements AlbumSetDataLoader.DataListener {
           
  • 檢視 AlbumSetSlidingWindow 事件
package com.android.gallery3d.ui;

// 這裡實作了上述的監聽事件
public class AlbumSetSlidingWindow implements AlbumSetDataLoader.DataListener {

    public static interface Listener {
        public void onSizeChanged(int size);
        public void onContentChanged();
    }

    @Override
    public void onContentChanged(int index) {
        ...
        // 這裡回調了自己的 onContentChanged 事件
        if (mListener != null && isActiveSlot(index)) {
            mListener.onContentChanged();
        }
    }
    
    
    @Override
    public void onSizeChanged(int size) {
        ...
        // 這裡回調了自己的 onSizeChanged 事件
        if (mListener != null) mListener.onSizeChanged(mSize);
        ...

    }
}

           
  • grep 指令檢視所有注冊該監聽 implements AlbumSetSlidingWindow.Listener

    grep -irn “implements AlbumSetSlidingWindow.Listener” ./路徑

發現隻有唯一一處
src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java:234:    private class MyCacheListener implements AlbumSetSlidingWindow.Listener
           
  • 檢視 AlbumSetSlotRenderer 接受的回調事件
package com.android.gallery3d.ui;

public class AlbumSetSlotRenderer extends AbstractSlotRenderer {

    private class MyCacheListener implements AlbumSetSlidingWindow.Listener {

        @Override
        public void onSizeChanged(int size) {
            mSlotView.setSlotCount(size);
        }

        @Override
        public void onContentChanged() {
            // SlotView重新整理界面
            mSlotView.invalidate();
        }
    }
    
}

           
  • 檢視 SlotView.invalidate() 重新整理界面函數
package com.android.gallery3d.ui;

public class SlotView extends GLView {

    // invalidate() 未重寫,故方法在 GLView
}


           
  • 檢視 GLView.invalidate() 重新整理界面函數
// Request re-rendering of the view hierarchy.
    // This is used for animation or when the contents changed.
    public void invalidate() {
        GLRoot root = getGLRoot();
        if (root != null) root.requestRender();
    }
           
  • 上述 root.requestRender() 就是請求渲染一幀資料,之後走到Renderer的onDrawFrame方法
package com.android.gallery3d.app.dualcam3d.gl;

public class Renderer implements GLSurfaceView.Renderer {

    @Override
    public void onDrawFrame(GL10 gl) {
        if (mImageBitmap == null) {
            return;
        }

        updateImage();
        updateMatrix();

        GLES20.glClearColor(0, 0, 0, 0);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
        mMesh.render(mShader);
    }
           

2. 渲染

2.1 檢視 AlbumSetPage.GLView 的 render 方法

package com.android.gallery3d.app;

public class AlbumSetPage extends ActivityState implements OnClickListener, ..{


    private final GLView mRootPane = new GLView() {
       @Override
        protected void render(GLCanvas canvas) {
            ...
            super.render(canvas);
            canvas.restore();
        } 
    };
}
           

2.2 GLView 的 render 方法

package com.android.gallery3d.ui;

public class GLView {

    protected void render(GLCanvas canvas) {
        ...
        for (int i = 0, n = getComponentCount(); i < n; ++i) {
            renderChild(canvas, getComponent(i));
        }
        ...
    }
    
    protected void renderChild(GLCanvas canvas, GLView component) {
        ...
        //這裡component就是 SlotView,用于繪制每個專輯
        component.render(canvas);
        ...
    }
}

           

2.3 SlotView 的 render 方法

package com.android.gallery3d.ui;

public class SlotView extends GLView {


    @Override
    protected void render(GLCanvas canvas) {
        super.render(canvas);

        ...
        // renderItem就是對每一個專輯進行繪制
        for (int i = mLayout.mVisibleEnd - 1; i >= mLayout.mVisibleStart; --i) {
            int r = renderItem(canvas, i, 0, paperActive);
            if ((r & RENDER_MORE_FRAME) != 0) more = true;
            if ((r & RENDER_MORE_PASS) != 0) requestedSlot[requestCount++] = i;
        }

        ...
    }
    
    private int renderItem(
            GLCanvas canvas, int index, int pass, boolean paperActive) {
        canvas.save(GLCanvas.SAVE_FLAG_ALPHA | GLCanvas.SAVE_FLAG_MATRIX);
        ...
        //mRenderer就是 AlbumSetSlotRenderer
        int result = mRenderer.renderSlot(
                canvas, index, pass, rect.right - rect.left, rect.bottom - rect.top);
        ...
    }
           

2.4 檢視 AlbumSetSlotRenderer.renderSlot

package com.android.gallery3d.ui;

public class AlbumSetSlotRenderer extends AbstractSlotRenderer {


    @Override
    public int renderSlot(GLCanvas canvas, int index, int pass, int width, int height) {
        AlbumSetEntry entry = mDataWindow.get(index);
        int renderRequestFlags = 0;

        // 增加非空判斷
        if(null == entry){
            Log.e(TAG, "render content error: entry is null!");
            return renderRequestFlags;
        }

        // 繪制專輯顯示的縮略圖
        renderRequestFlags |= renderContent(canvas, entry, width, height);
        // 繪制顯示檔案夾名稱、數目、檔案夾icon的Label
        renderRequestFlags |= renderLabel(canvas, entry, width, height);
        // 繪制長按選擇專輯時的藍色圖層
        renderRequestFlags |= renderOverlay(canvas, index, entry, width, height);
        // 畫分割線
        renderRequestFlags |= renderDivider(canvas, width, height);
        return renderRequestFlags;
    }
           

最終所有專輯都通過canvas繪制出來,canvas是通過OpenGL ES的GLES20.glDrawArrays(type, 0, count)來繪制的,具體自行檢視GLES20Canvas類。

繼續閱讀