iT邦幫忙

0

Android Curv Gradient 曲線漸層2-優化篇

前言

延續前篇Android Curv Gradient 曲線漸層
過了一個月...終於改好啦!!!!

效率比較

機型:同樣使用Oppo R17 Pro
繪製數量:190個
監控工具:FPS監測工具 wasabeef/Takt
監控工具這邊說明一下,前篇有提到在這樣的測試條件下會有明顯的卡頓問題,因此想到最直觀的檢測結果應該就是用FPS吧,但實際開發一開始是使用AndroidProfiler,監控記憶體以及物件的狀況,大概類似下面這樣,可以從記憶體走勢、物件創建狀況為參考,逐一去排除可能造成卡頓的問題。
https://ithelp.ithome.com.tw/upload/images/20210506/20126774vcilFa6Q9Z.png

首先我做一個一基準,先全部用TextView觀察整個使用狀況(由於這邊不支援Gif,有興趣請點外部連結出去看)
操作過程
生成RecyclerView FPS:2.3
快速滑動FPS:22.6 ~ 60
除了一看開使生成RecyclerView有些微卡頓,在使用中感覺不出卡頓

接下來使用舊版的也就是前篇未優化的版本
生成RecyclerView FPS:7.5
快速滑動FPS:2.6 ~ 7.5
操作過程

優化版
生成RecyclerView FPS:1.3
快速滑動FPS:17.2 ~ 51.3
操作過程

從數據部分可以看到在按下Load鈕,生成RecyclerView即便用完全原生的TextView也是會有明顯的卡頓狀況,但是為何使用舊版的相比起來反而FPS比較高,我後來又測試了多次,三個版本大約都落在10FPS內,所以就不多探究這個部分。
快速滑動過程應該不用看數據就可以感覺到舊版有明顯的卡頓,FPS部分也確實有明顯的落差。

實際優化方案

發想

初期也是看了Profiler裡面,會產生大量的物件,特別是Point, LinearGradient。Point改用兩組Integer完全沒有改善,LinearGradient又省不了,本來重複使用LinearGradient,至於mPositions參數的變化用反射的方式修改,但沒試出來。一氣之下就打算用改用JNI試試,主要是過去有個經驗,把一模一樣邏輯從Java搬到C直接快3倍,雖然有點麻煩但直覺肯定會變快。

實作

由於主要是要解決大量Java物件產生的問題,因此就只有在Java層取的一些基本設定,還有UI尺寸之後就直接送到C去計算以及渲染。計算部分流程都相同,主要差別在於LinearGradient直線渲染部分必須要自行解決

以下程式碼是從原始碼native-lib.cpp裡面擷取,有興趣請直接到Github查看

將從Java傳過來的int color轉為RGB

int* color0 = new int[3];
color0[0] = *tmpColor >> 16 & 0xff;
color0[1] = *tmpColor >> 8 & 0xff;
color0[2] = *tmpColor & 0xff;
//整張圖的尺寸
int* tmpArray = new int[width * height];
for(int j = 0; j < width; j++) {
    //漸變點的座標
    int centerPosition = ((float) height)  * fullPositions[j];
    for (int i = 0; i < height; i++) {
        int red, green, blue;
        //計算每個Pixel顏色
        if(i < centerPosition) {
            float ratio = (float)i / (float)centerPosition;
            red = color0[0] + ((float)(color1[0] - color0[0]) * ratio);
            green = color0[1] + ((float)(color1[1] - color0[1]) * ratio);
            blue = color0[2] + ((float)(color1[2] - color0[2]) * ratio);
        }
        else{
            int secondHalf = height - centerPosition;
            float ratio = (float)(i - centerPosition) / (float)secondHalf;
            red = color1[0] + ((float)(color2[0] - color1[0]) * ratio);
            green = color1[1] + ((float)(color2[1] - color1[1]) * ratio);
            blue = color1[2] + ((float)(color2[2] - color1[2]) * ratio);
        }
        tmpArray[i * width + j] = 255 << 24 | (red << 16) | (green << 8) | blue;
    }
}

透過上面的程式碼已經將所有Pixel的顏色都填好了,接下來就是回到Java的部分產生Bitmap並且繪製就完成了

Bitmap bmp = Bitmap.createBitmap(tmpArray, width, height, Bitmap.Config.ARGB_8888);
canvas.drawBitmap(bmp, 0, 0, paint);

結論

優化部分大致做到這個階段,用起來還算順暢了,由於平常沒什麼機會寫C,程式碼應該還有很大的優化空間,但制哨初步的目的達到了,有空再來改寫


尚未有邦友留言

立即登入留言