无码人妻精一区二区三区,eeuss影院www在线观看,无码精品久久久久久人妻中字,日韩av高清在线看片

推薦新聞
Android 中的 Hardware Layer 詳解
發(fā)布者:深藍互聯(lián)
發(fā)布時間:2019-07-30
點擊:次

硬件加速與軟件加速

很多人會把 Android 中的硬件加速和 Hardware Layer 搞混,會以為啟用了硬件加速,就是啟用了 Hardware Layer. 所以在說 Hardware Layer 之前,我們先說一下硬件加速

關(guān)于硬件加速的比較詳細的文章,推薦大家看這三篇

  1. Android硬件加速原理與實現(xiàn)簡介
  2. 理解Android硬件加速的小白文
  3. 官方文檔:Hardware acceleration

硬件加速,實際上應該叫 GPU 加速,軟硬件加速的區(qū)別主要是圖形的繪制究竟是 GPU 來處理還是 CPU,如果是 GPU,就認為是硬件加速繪制,反之,則是軟件繪制

目前的 Android 版本, 默認情況下都是開了硬件加速的,如果你的 App 沒有特殊聲明,那么硬件加速就是默認開啟的

上面三篇文章都有介紹,代碼級別和原理級別都講的比較深,這里我從 Systrace 的角度來給大家展示一下硬件加速下 App 的繪制與軟件加速的區(qū)別

硬件加速 App 的表現(xiàn)

由于默認情況下就是硬件加速,所以我們以最常見的滑動桌面為例,看一下硬件加速情況下 App 在 Systrace 上的表現(xiàn)

硬件加速情況下,App 存在主線程和渲染線程,一幀的繪制是主線程和渲染線程一起配合執(zhí)行的

 

我們把 Systrace 放大,來看每一幀主線程和渲染線程是怎么工作的,GPU 是什么時候介入工作,實現(xiàn)”加速”的

 

GPU 的真正介入是在 RenderThread 中的部分操作中

軟件加速 App 的表現(xiàn)

對應的,軟件加速我們也找一個 App 來進行演示:云閃付

首先放一張全景圖,可以看到軟件渲染下,只有主線程,沒有渲染線程,所有的渲染工作,都在主線程完成,同時可以看到,軟件渲染下,每一幀的執(zhí)行時間都非常長,超過1個 Vsync 周期,所以滑動的時候會一卡一卡的,非常難受 Systrace 下載

 

我們把 Systrace 放大,來看每一幀主線程是怎么工作的

 

總結(jié)

通過上面的對比以及推薦的三篇文章的閱讀,你應該對硬件渲染和軟件渲染的區(qū)別了然于胸,這里總結(jié)一下

  1. 硬件渲染情況下,app 存在主線程和渲染線程;軟件渲染情況下, app 只有主線程沒有渲染線程
  2. 硬件渲染情況下,app 最終繪制是借助 GPU 來實現(xiàn) ;軟件渲染情況下, app 最終繪制是使用 CPU 來實現(xiàn)(調(diào)用 skia 庫)
  3. 硬件渲染情況下,App 的性能是要優(yōu)于軟件渲染的
  4. 由于部分 api 硬件渲染不支持,所以只能是要軟件渲染,做 App 開發(fā)的時候,應該盡量避免使用此類 Api(支持情況可以直接在 Android 官方文檔里面查看 :https://developer.android.google.cn/guide/topics/graphics/hardware-accel)

Software Layer VS Hardware Layer

說完了硬件渲染,我們來說一下 Software Layer 和 Hardware Layer , 這兩個概念主要是針對 View 的說的, 與此時 App 是硬件渲染還是軟件渲染沒有直接關(guān)系(但是有依賴關(guān)系,稍后會講).

一個 View 的 layerType 共有三種狀態(tài)( 后面的英文是官方文檔,先讀英文我再講解):

  1. LAYER_TYPE_NONE : Indicates that the view does not have a layer.
  2. LAYER_TYPE_SOFTWARE :Indicates that the view has a software layer. A software layer is backed by a and causes the view to be rendered using Android’s software rendering pipeline, even if hardware acceleration is enabled
  3. LAYER_TYPE_HARDWARE :Indicates that the view has a hardware layer. A hardware layer is backed by a hardware specific texture (generally Frame Buffer Objects or FBO on OpenGL hardware) and causes the view to be rendered using Android’s hardware rendering pipeline, but only if hardware acceleration is turned on for the view hierarchy. When hardware acceleration is turned off, hardware layers behave exactly as LAYER_TYPE_SOFTWARE

LAYER_TYPE_NONE

默認情況下,所有的 View 都是這個 layerType,這種情況下,這個 View 不會做任何的特殊處理,該怎么走怎么走

LAYER_TYPE_SOFTWARE

Software layerType , 標識這個 View 有一個軟件實現(xiàn)的 Layer ,怎么個軟件實現(xiàn)法呢,實際上就是把這個 View,根據(jù)一定的條件,變成一個 Bitmap 對象

android/view/View.java
 Bitmap bitmap = createBitmap(mResources.getDisplayMetrics(),
        width, height, quality);

Software layer 的作用如下

  1. When the application is not using hardware acceleration, a software layer is useful to apply a specific color filter and/or blending mode and/or to a view and all its children.(當應用程序不使用硬件加速時,Software layer 可用于將特定的顏色過濾器、混合模式或半透明應用于 View 及其所有子 View)
  2. When the application is using hardware acceleration, a software layer is useful to render drawing primitives not supported by the hardware accelerated pipeline. It can also be used to cache a complex view tree into a texture and reduce the complexity of drawing operations. For instance, when a complex view tree with a translation, a software layer can be used to render the view tree only once.(當應用程序使用硬件加速時,軟件層可用于呈現(xiàn)硬件加速管道不支持的繪圖基元。 它還可用于將復雜視圖樹緩存到紋理中,并降低繪制操作的復雜性。 例如,在使用轉(zhuǎn)換動畫復雜視圖樹時,可以使用軟件層僅渲染視圖樹一次)
  3. Software layers should be avoided when the affected view tree updates often. Every update will require to re-render the software layer, which can potentially be slow (particularly when hardware acceleration is turned on since the layer will have to be uploaded into a hardware texture after every update(當受影響的視圖樹經(jīng)常更新時,應避免使用軟件層。 每次更新都需要重新渲染軟件層,這可能會很慢(特別是在打開硬件加速時,因為每次更新后都必須將圖層上傳到硬件紋理中)

LAYER_TYPE_HARDWARE

Hardware layerType ,標識這個 View 有一個硬件實現(xiàn)的 Layer ,通過第一小節(jié)我知道,這里的硬件指的是 GPU ,那么硬件實現(xiàn)的 Layer 顧名思義就是通過 GPU 來實現(xiàn)的,通常是OpenGL硬件上的幀緩沖對象或FBO(離屏渲染 Buffer)

注意:這里 Hardware layerType 是依賴硬件加速的,如果硬件加速開啟,那么才會有 FBO 或者幀緩沖 ; 如果硬件加速關(guān)閉,那么就算你設(shè)置一個 View 的 LayerType 是 Hardware Layer ,也會按照 Software Layer 去做處理

Hardware layer 的作用:

  1. A hardware layer is useful to apply a specific color filter and/or blending mode and/or to a view and all its children.(硬件層可用于將特定顏色過濾器和/或混合模式和/或半透明應用于視圖及其所有子視圖
    1. A hardware layer can be used to cache a complex view tree into a texture and reduce the complexity of drawing operations. For instance, when a complex view tree with a translation, a hardware layer can be used to render the view tree only once.(hardware layer 可用于將復雜視圖樹緩存到紋理中,并降低繪制操作的復雜性。 例如,在使用轉(zhuǎn)換動畫復雜視圖樹時,可以使用硬件層僅渲染視圖樹一次,這個是最主要的一個點)
    2. A hardware layer can also be used to increase the rendering quality when rotation transformations are applied on a view. It can also be used to prevent potential issues when applying 3D transforms on a view (在視圖上應用旋轉(zhuǎn)變換時,還可以使用硬件層來提高渲染質(zhì)量。 它還可用于在視圖上應用3D變換時防止?jié)撛诘募羟袉栴})

 

而設(shè)置 Hardware Layer 對 alpha\translation \ scale \ rotation \ 這幾個屬性動畫性能有幫助(同樣的, 設(shè)置 Software Layer 也有相同的功效,下面的小例子環(huán)節(jié)會有詳細的講解),具體的使用如下

動畫開始前,設(shè)置 LayerType 為 LAYER_TYPE_HARDWARE(代碼為官方示例)

view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator.ofFloat(view, "rotationY", 180).start();

動畫結(jié)束的時候,重新設(shè)置為LAYER_TYPE_NONE(代碼為官方示例)

view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator  = ObjectAnimator.ofFloat(view, "rotationY", 180);
.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd( animation) {
        view.setLayerType(View.LAYER_TYPE_NONE, null);
    }
});
.start();

由于 Hardware Layer 的特性,屬性動畫( alpha \ translation \ scale \ rotation \ )過程中只更新 View 的 property,不會每一幀都去銷毀和重建 FBO,其動畫性能會有很大的提升。當然這里要注意屬性動畫的過程中( 比如 AnimationUpdate 回調(diào)中),不要做除了上述屬性更新之外的其他事情,比如添加刪除子 View、修改 View 的顯示內(nèi)容等,這會使得 FBO 失效,性能反而變差

總結(jié)

  1. 從上面對 Hardware Layer 和 Software Layer 的描述可以看到,
    Software Layer 是對 Hardware Layer 的一個補充,如果 App 處于某種情況不能使用 Hardware Layer ,那么 Software Layer 就會派上用場 。 Hardware Layer 不支持的 API 的實現(xiàn)也得用 Software Layer 來實現(xiàn)
  2. Software Layer 和 Hardware Layer 都可以對 View 進行操作,比如顏色過濾器、混合模式等
  3. Software Layer 和 Hardware Layer 對 alpha \ translation \ scale \ rotation \ pivot 這幾個屬性動畫性能有幫助,這也是 Software Layer 和 Hardware Layer 使用最頻繁的優(yōu)化 (也就是我們常說的 : 在做上述動畫的時候,在動畫開始前,將這個 View 的 LayerType 設(shè)置為 LAYER_TYPE_HARDWARE ,在動畫結(jié)束后,將 layerType 重新設(shè)置為 LAYER_TYPE_NONE , 設(shè)置回來的原因是 Hardware Layer 使用的是 Video Memory,設(shè)置為 NONE 之后這部分使用的內(nèi)存將會回收 )

不正確使用 LayerType 導致的性能問題案例

不正確使用 Software layer 引起的性能問題

看 Trace 經(jīng)常會有這樣的情況出現(xiàn) , 我們知道 Software layer 的生成過程本質(zhì)上是生成一個 Bitmap Cache ,這個 Cache 的生成是很耗時的, 從下面的 Trace 也可以看出來,每一幀都比一個 Vsync 周期要長。

之所以下面的 Trace 每一幀都去調(diào)用了 buildDrawingCache/SW ,是因為每一幀的過程中,這個 View 的內(nèi)容進行了更新,導致 Cache 失效,所以每一幀都去觸發(fā)銷毀 Cache 和重建 Cache,導致界面滑動卡頓

下面這個 Trace 是微信朋友圈的大圖滑動情況 Trace 在 Github 上可以下載

 

放大來看,每一幀都在做 buildDrawingCache 操作,說明每一幀的緩存都失效了,在進行銷毀和重建,性能極差,滑動的時候頓挫感非常嚴重

 

代碼流程

簡單看一下 LAYER_TYPE_HARDWARE 的代碼流程,詳細的流程可以看上面推薦的文章

buildLayer  -> buildDrawingCache -> buildDrawingCacheImpl
public void buildLayer() {
    if (mLayerType == LAYER_TYPE_NONE) return;
    ......
    switch (mLayerType) {
        case LAYER_TYPE_HARDWARE:  // 硬件渲染
            updateDisplayListIfDirty();
            if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) {
                attachInfo.mThreadedRenderer.buildLayer(mRenderNode);
            }
            break;
        case LAYER_TYPE_SOFTWARE:
            buildDrawingCache(true);  // 軟件渲染
            break;
    }
}

其中 buildDrawingCache 的實現(xiàn), 可以看到對應的 Trace 就是在這里打印的:

public void buildDrawingCache(boolean autoScale) {
    if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ?
            mDrawingCache == null : mUnscaledDrawingCache == null)) {
        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW,
                    "buildDrawingCache/SW Layer for " + getClass().getSimpleName());
        }
        try {
            buildDrawingCacheImpl(autoScale);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }
}

不正確使用 Hardware layer 引起的性能問題

不正確使用 Hardware Layer 和不正確使用 Software Layer 會引起相同的性能問題,比如下面這個場景 (桌面打開文件夾),由于開發(fā)的實現(xiàn)問題,多個文件夾小圖標都被設(shè)置了 Hardware LayerType , 導致 RenderThread 非常耗時,又因為每一幀其中的內(nèi)容都在變,導致每一幀的 Hardware Layer 都失效,被銷毀后重建,所以就有了下面的 Systrace 所展示的情況

Trace 在 Github 上可以下載

 

我們放大 RenderThread 的一幀來看

 

Debug 工具

我們可以在 設(shè)置 - 輔助功能 - 開發(fā)者選項 - 顯示硬件層更新(Show hardware layers updates) 這個工具來追蹤硬件層更新導致的性能問題 。

當 View 渲染 Hardware Layer 的時候整個界面會閃爍綠色,正常情況下,它應該在動畫開始的時候閃爍一次(也就是 Layer 渲染初始化的時候),后續(xù)的動畫不應該再有綠色出現(xiàn);如果你的 View 在整個動畫期間保持綠色不變,這就是持續(xù)的緩存失效問題了
查看 Systrace 也可以發(fā)現(xiàn)相同的問題, 兩個工具可以一起使用,早些發(fā)現(xiàn)動畫的性能問題。

總結(jié)

  1. 記住 LayerType 使用的場景:View 做 alpha \ translation \ scale \ rotation \ 這幾個屬性動畫
  2. 做動畫的時候,如果可以,盡量多使用 Hardware Layer ,使用完成后記得設(shè)置為 None,除非有硬件層不支持的 api,才去考慮使用 Software Layer
  3. 如果是使用 setAlpha(), AlphaAnimation, or ObjectAnimator 來設(shè)置 View 的透明度的話,默認就會走 off-screen buffer , 所以如果你操作的 View 比較大的話,也可以把這個 View 的 Type 設(shè)置為 LAYER_TYPE_HARDWARE(官方建議)
  4. 在某些情況下,實際上 Hardware Layer 可能要做非常多的工作,而不僅僅是渲染視圖。緩存一個層需要花費時間,因為這一步要劃分為兩個過程:首先,視圖渲染入 GPU 上的一個層中,然后,GPU 再渲染那個層到窗口,如果 View 的渲染十分簡單(比如一個純色),那么在初始化的時候設(shè)置 Hardware Layer 可能增加不必要的開銷
  5. 對所有緩存來講,存在一個緩存失效的可能性。動畫運行時,如果某個地方調(diào)用了View.invalidate( ),那么 Layer 就不得不重新渲染一遍。倘若不斷地失效,你的Hardware Layer 實際上要比不添加任何 Layer 性能更差(下面的例子可以佐證),因為Hardware Layer 在設(shè)置緩存的時候增加了開銷。如果你不斷的重緩存 Layer,會對性能造成極大地負擔(做動畫的 View 越復雜,帶來的負擔就越重)

LayerType 對動畫性能的影響示例

示例

代碼

為了說明上面所說的情況,我們用一個小例子來做示例,演示在各種情況下,其性能表現(xiàn),代碼非常簡單(代碼項目地址 :https://github.com/Gracker/Android_HardwareLayer_Example), 項目 Systrace 文件夾中包含此文章中涉及的所有例子(這都是好東西,值得收藏)

  1. 兩個 TextView ,一個負責開始動畫,一個負責做動畫
  2. 動畫類型有 TRANSLATION_X 、ALPHA、TRANSLATION_Y、SCALE_X、SCALE_Y
  3. 我們會控制 AnimatorListener 和 AnimatorUpdateListener ,使得動畫的實現(xiàn)不一樣
    1. onAnimationStart 和 onAnimationEnd 中主要是設(shè)置是否啟用 LAYER_TYPE_HARDWARE 或者 LAYER_TYPE_SOFTWARE
    2. onAnimationUpdate 主要演示如果在動畫過程中改變了 View 的內(nèi)容,會造成什么影響

 

  //設(shè)置動畫
  animatorSet = new AnimatorSet();
  objectAnimator1 = ObjectAnimator.ofFloat(animationText, View.TRANSLATION_X,150);
  objectAnimator2 = ObjectAnimator.ofFloat(animationText, View.ALPHA,0);
  objectAnimator3 = ObjectAnimator.ofFloat(animationText, View.TRANSLATION_Y,150);
  objectAnimator4 = ObjectAnimator.ofFloat(animationText, View.SCALE_X,150);
  objectAnimator5 = ObjectAnimator.ofFloat(animationText, View.SCALE_Y,150);
  animatorSet.playTogether(objectAnimator1,
            objectAnimator2,objectAnimator3,
            objectAnimator4,objectAnimator5);
  animatorSet.setDuration(500);
  
  //添加動畫監(jiān)聽器
  objectAnimator1.addListener(new Animator.AnimatorListener() {
      @Override
      public void onAnimationStart(Animator animator) {
          animationText.setLayerType(View.LAYER_TYPE_HARDWARE,null);
          // animationText.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
      }

      @Override
      public void onAnimationEnd(Animator animator) {
          animationText.setLayerType(View.LAYER_TYPE_NONE,null);
      }
  });

  objectAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator valueAnimator) {
          // text.setText(String.format("%s%d", text.getText().toString(), i));
          // i ++ ;
      }
  });
  //開始動畫
  startText.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
          animatorSet.start();
      }
  });

統(tǒng)計工具:GFXInfo

為了得到準確的數(shù)據(jù),我們使用 gfxinfo 得到的數(shù)據(jù)來進行對比( adb shell dumpsys gfxinfo)

 

gfxInfo 記錄的是每一幀的耗時,我們重點看下面幾個指標

  1. Janky Frames :超過 16 ms 的幀數(shù) (超過 16 ms 不一定會卡頓,但是會增加卡頓情況出現(xiàn)的風險)
  2. 耗時幀統(tǒng)計:可以看到大部分幀的區(qū)間,以及最大耗時

案例一:Normal Layer + 不動態(tài)更新 View 內(nèi)容

代碼

AnimatorListener 和 AnimatorUpdateListener 都不重寫, 如下,函數(shù)內(nèi)的都注釋掉
objectAnimator1.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animator) {
    }

    @Override
    public void onAnimationEnd(Animator animator) {
    }
});

objectAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
    }
});

Systrace 現(xiàn)象

可以看到有部分黃幀, 渲染線程中 flush commands 方法執(zhí)行比較久Systrace 下載

 

gfxInfo 數(shù)據(jù)

可以看到 Janky Frames 比例為 46%,99th percentile: 32ms ,說明性能比較差,同時 Number High input latency = 30 說明主線程的負載是比較高的

Total frames rendered: 30
Janky frames: 14 (46.67%)
50th percentile: 16ms
90th percentile: 29ms
95th percentile: 32ms
99th percentile: 32ms
Number Missed Vsync: 0
Number High input latency: 30
Number Slow UI thread: 0
Number Slow bitmap uploads: 0
Number Slow issue draw commands: 0
Number Frame deadline missed: 0
HISTOGRAM: 5ms=0 6ms=0 7ms=0 8ms=0 9ms=0 10ms=2 11ms=2 12ms=5 13ms=1 14ms=2 
15ms=1 16ms=3 17ms=2 18ms=0 19ms=0 20ms=0 21ms=1 22ms=1 23ms=1 24ms=1 25ms=2 
26ms=2 27ms=0 28ms=1 29ms=1 30ms=0 31ms=0 32ms=2 34ms=0 36ms=0 38ms=0 40ms=0

案例二:Software Layer + 不動態(tài)更新 View 內(nèi)容

代碼

 objectAnimator1.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animator) {
        animationText.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
    }

    @Override
    public void onAnimationEnd(Animator animator) {
        animationText.setLayerType(View.LAYER_TYPE_NONE,null);
        i = 0;
    }
});

objectAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
    }
});

Systrace 現(xiàn)象

第一幀執(zhí)行 buildDrawingCache/SW Layer for AppCompatTextView ,后續(xù)的屬性動畫中,都沒有在執(zhí)行這個方法,可以看到動畫過程中所有的幀都是綠色,說明性能很好Systrace 下載

 

gfxInfo 數(shù)據(jù)

可以看到 Janky Frames 比例為 3%,99th percentile: 16ms ,說明性能非常好,同時 Number High input latency = 0 說明主線程的負載是比較低的

Total frames rendered: 31
Janky frames: 1 (3.23%)
50th percentile: 9ms
90th percentile: 12ms
95th percentile: 16ms
99th percentile: 16ms
Number Missed Vsync: 0
Number High input latency: 0
Number Slow UI thread: 1
Number Slow bitmap uploads: 0
Number Slow issue draw commands: 0
Number Frame deadline missed: 1
HISTOGRAM: 5ms=2 6ms=2 7ms=4 8ms=3 9ms=5 10ms=11 11ms=0 12ms=1 13ms=0 14ms=1 
15ms=0 16ms=2 17ms=0 18ms=0 19ms=0 20ms=0 21ms=0 22ms=0 23ms=0 24ms=0 25ms=0 
26ms=0 27ms=0 28ms=0 29ms=0 30ms=0 31ms=0 32ms=0 34ms=0 36ms=0 38ms=0 40ms=0

案例三:Hardware Layer + 不動態(tài)更新 View 內(nèi)容

代碼

objectAnimator1.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animator) {
        animationText.setLayerType(View.LAYER_TYPE_HARDWARE,null);
    }

    @Override
    public void onAnimationEnd(Animator animator) {
        animationText.setLayerType(View.LAYER_TYPE_NONE,null);
    }
});

objectAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
    }
});

Systrace 現(xiàn)象

可以看到,動畫過程全是綠幀,性能非常好Systrace 下載

 

gfxInfo 數(shù)據(jù)

可以看到 Janky Frames 比例為 0%,99th percentile: 14ms ,說明性能非常好,同時 Number High input latency = 0 說明主線程的負載是非常低的

Total frames rendered: 31
Janky frames: 0 (0.00%)
50th percentile: 7ms
90th percentile: 9ms
95th percentile: 12ms
99th percentile: 14ms
Number Missed Vsync: 0
Number High input latency: 0
Number Slow UI thread: 0
Number Slow bitmap uploads: 0
Number Slow issue draw commands: 0
Number Frame deadline missed: 0
HISTOGRAM: 5ms=3 6ms=2 7ms=15 8ms=7 9ms=2 10ms=0 11ms=0 12ms=1 13ms=0 14ms=1 
15ms=0 16ms=0 17ms=0 18ms=0 19ms=0 20ms=0 21ms=0 22ms=0 23ms=0 24ms=0 25ms=0 
26ms=0 27ms=0 28ms=0 29ms=0 30ms=0 31ms=0 32ms=0 34ms=0 36ms=0 38ms=0 40ms=0

案例四:Normal Layer + 動態(tài)更新 View 內(nèi)容

代碼

objectAnimator1.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animator) {
    }

    @Override
    public void onAnimationEnd(Animator animator) {
        i = 0;
    }
});

objectAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
        animationText.setText(String.format("%s%d", animationText.getText().toString(), i));
        i ++ ;
    }
});

Systrace 現(xiàn)象

可以看到動畫過程中有部分黃幀,部分幀的 Animation、measure、layout、draw 比較耗時Systrace 下載

 

gfxInfo 數(shù)據(jù)

可以看到 Janky Frames 比例為 38%,99th percentile: 29ms ,說明性能比較差,同時 Number High input latency = 31 說明主線程的負載是比較高的

Total frames rendered: 31
Janky frames: 12 (38.71%)
50th percentile: 14ms
90th percentile: 25ms
95th percentile: 29ms
99th percentile: 29ms
Number Missed Vsync: 0
Number High input latency: 31
Number Slow UI thread: 0
Number Slow bitmap uploads: 0
Number Slow issue draw commands: 0
Number Frame deadline missed: 0
HISTOGRAM: 5ms=0 6ms=0 7ms=1 8ms=2 9ms=4 10ms=1 11ms=1 12ms=4 13ms=2 14ms=1 
15ms=2 16ms=2 17ms=1 18ms=2 19ms=0 20ms=2 21ms=1 22ms=0 23ms=0 24ms=1 25ms=1 
26ms=1 27ms=0 28ms=0 29ms=2 30ms=0 31ms=0 32ms=0 34ms=0 36ms=0 38ms=0 40ms=0

案例五:Software Layer + 動態(tài)更新 View 內(nèi)容

代碼

objectAnimator1.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animator) {
        animationText.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
    }

    @Override
    public void onAnimationEnd(Animator animator) {
        animationText.setLayerType(View.LAYER_TYPE_NONE,null);
        i = 0;
    }
});

objectAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
        animationText.setText(String.format("%s%d", animationText.getText().toString(), i));
        i ++ ;
    }
});

Systrace 現(xiàn)象

由于每一幀都在更新內(nèi)容,所以每次 buildDrawingCache 生成的 Bitmap 都會被銷毀和重建,此時的瓶頸都在主線程中,由于 buildDrawingCache 每一幀都執(zhí)行,導致 Animation 和 Draw 的執(zhí)行時間都很長Systrace 下載

 

gfxInfo 數(shù)據(jù)

可以看到 Janky Frames 比例為 41%,99th percentile: 32ms ,說明性能比較差,同時 Number High input latency = 18 說明主線程的負載是比較高的

Total frames rendered: 29
Janky frames: 12 (41.38%)
50th percentile: 14ms
90th percentile: 30ms
95th percentile: 31ms
99th percentile: 32ms
Number Missed Vsync: 0
Number High input latency: 18
Number Slow UI thread: 4
Number Slow bitmap uploads: 0
Number Slow issue draw commands: 0
Number Frame deadline missed: 4
HISTOGRAM: 5ms=0 6ms=1 7ms=0 8ms=0 9ms=0 10ms=1 11ms=6 12ms=3 13ms=2 14ms=3 
15ms=0 16ms=1 17ms=1 18ms=1 19ms=2 20ms=0 21ms=1 22ms=0 23ms=0 24ms=2 25ms=1 
26ms=0 27ms=1 28ms=0 29ms=0 30ms=1 31ms=1 32ms=1 34ms=0 36ms=0 38ms=0 40ms=0

案例六:Hardware Layer + 動態(tài)更新 View 內(nèi)容

代碼

objectAnimator1.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animator) {
        animationText.setLayerType(View.LAYER_TYPE_HARDWARE,null);
    }

    @Override
    public void onAnimationEnd(Animator animator) {
        animationText.setLayerType(View.LAYER_TYPE_NONE,null);
        i = 0;
    }
});

objectAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
        animationText.setText(String.format("%s%d", animationText.getText().toString(), i));
        i ++ ;
    }
});

Systrace 現(xiàn)象

與 Software Layer 情況類似,由于每一幀都在更新內(nèi)容,所以每次 drawLayer 生成的 Buffer 都會被銷毀和重建,此時的瓶頸都在主線程 + 渲染線程中,由于每一幀內(nèi)容更新和 Buffer 銷毀重建,導致主線程和渲染線程執(zhí)行時間都很長,性能比較差Systrace 下載

 

gfxInfo 數(shù)據(jù)

可以看到 Janky Frames 比例為 46%,99th percentile: 32ms ,說明性能比較差,同時 Number High input latency = 30 說明主線程的負載是比較高的

Total frames rendered: 30
Janky frames: 14 (46.67%)
50th percentile: 16ms
90th percentile: 29ms
95th percentile: 32ms
99th percentile: 32ms
Number Missed Vsync: 0
Number High input latency: 30
Number Slow UI thread: 0
Number Slow bitmap uploads: 0
Number Slow issue draw commands: 0
Number Frame deadline missed: 0
HISTOGRAM: 5ms=0 6ms=0 7ms=0 8ms=0 9ms=0 10ms=2 11ms=2 12ms=5 13ms=1 14ms=2 
15ms=1 16ms=3 17ms=2 18ms=0 19ms=0 20ms=0 21ms=1 22ms=1 23ms=1 24ms=1 25ms=2 
26ms=2 27ms=0 28ms=1 29ms=1 30ms=0 31ms=0 32ms=2 34ms=0 36ms=0 38ms=0 40ms=0

總結(jié)

從上面的六個案例可以看到,相同的動畫,在不同的 LayerType 之下,其性能表現(xiàn)差別很大,這還只是簡單的屬性動畫,如果碰到更加復雜的動畫,性能差別會更大。
我們對上面幾個案例和表現(xiàn)出來的性能數(shù)據(jù)做一下簡單的總結(jié):

  1. 如果只是單純的做動畫,不動態(tài)修改 View 的內(nèi)容,那么性能表現(xiàn)為 :Hardware Layer >= Software Layer > Normal Layer
  2. 如果做動畫同時動態(tài)修改 View 的內(nèi)容,那么性能表現(xiàn)為 :Normal Layer > Software Layer = Hardware Layer
  3. Hardware Layer 對動畫性能確實有很大的提升,但是如果你用不好,那么還不如不用
  4. 如果通過 Systrace 發(fā)現(xiàn)你做動畫的時候每一幀都在 buildDrawingCache/SW(主線程) 或者 buildLayer(渲染線程),那么請查看你的代碼的邏輯
  5. 有些情況下是由于系統(tǒng)的原因,比如圖片比 Cache 大,invalidate 邏輯問題,可以聯(lián)系手機廠商進行一起修改

 

關(guān)注深藍互聯(lián)公眾號
Copyright ? 2013-2025 深藍互聯(lián) 版權(quán)所有
友情鏈接: