Android FPS流暢度測(cè)試

前言:

流暢度,是頁(yè)面在滑動(dòng)、渲染等過(guò)程中的體驗(yàn)。Android系統(tǒng)要求每一幀都要在 16ms 內(nèi)繪制完成,平滑的完成一幀意味著任何特殊的幀需要執(zhí)行所有的渲染代碼(包括 framework 發(fā)送給 GPU 和 CPU 繪制到緩沖區(qū)的命令)都要在 16ms 內(nèi)完成,保持流暢的體驗(yàn)。如果沒(méi)有在期間完成渲染秒就會(huì)發(fā)生掉幀。掉幀是用戶體驗(yàn)中一個(gè)非常核心的問(wèn)題。丟棄了當(dāng)前幀,并且之后不能夠延續(xù)之前的幀率,這種不連續(xù)的間隔會(huì)容易會(huì)引起用戶的注意,也就是我們常說(shuō)的卡頓、不流暢。
導(dǎo)致掉幀的原因會(huì)有很多,這里只列出以下幾點(diǎn):
?花了非常多時(shí)間重新繪制界面中的大部分東西,這樣非常浪費(fèi)CPU周期;
?過(guò)度繪制嚴(yán)重,在繪制用戶看不到的對(duì)象上花費(fèi)了太多的時(shí)間
?有一大堆動(dòng)畫(huà)重復(fù)了一遍又一遍,消耗 CPU 、 GPU 資源
?頻繁的觸發(fā)垃圾回收。

追蹤性能方法

Hierarchy View
Overdraw
Rendering (渲染性能)

Hierarchy View

Hierarchy View 在Android SDK里自帶,常用來(lái)查看界面的視圖結(jié)構(gòu)是否過(guò)于復(fù)雜,用于了解哪些視圖過(guò)度繪制。還給出關(guān)于測(cè)量、布局、繪制的性能。


分析示例:如果red dot在一個(gè)葉子節(jié)點(diǎn)或者一個(gè)只有幾個(gè)子節(jié)點(diǎn)的ViewGroup上,可能會(huì)存在一些問(wèn)題。APP整體表現(xiàn)可能不壞,但是你要意識(shí)到那個(gè)節(jié)點(diǎn)為什么是紅色的!可以使用Systrace或者 TraceView做進(jìn)一步的分析。
如果ViewGroup的Measure 是紅色的,要分析一下它的子節(jié)點(diǎn)。
如果View存在黃色甚至紅色dot,可能在手機(jī)上的運(yùn)行效率并不慢,可能是由于view的數(shù)目過(guò)多造成的??梢允褂肧ystrace或者 TraceView做進(jìn)一步的分析。
如果一個(gè)層級(jí)結(jié)構(gòu)的根節(jié)點(diǎn)measure dot是紅色的,layout dot是紅色的,draw dot是黃色的,這是一種非常典型的情況,因?yàn)樗撬泄?jié)點(diǎn)的根節(jié)點(diǎn)。
如果一個(gè)有20+ view的層級(jí)結(jié)構(gòu)中,一個(gè)葉子節(jié)點(diǎn)draw dot是紅色的,那肯定是問(wèn)題,檢查一下它的onDraw方法。
官方介紹
https://developer.android.com/studio/profile/hierarchy-viewer-walkthru.html

Overdraw

Overdraw表示某些組件在屏幕上的一個(gè)像素點(diǎn)的繪制次數(shù)超過(guò) 1 次??梢酝ㄟ^(guò)開(kāi)發(fā)者選項(xiàng)里打開(kāi) “ 調(diào)試 GPU 過(guò)度繪制獲得相關(guān)信息。


用顏色來(lái)區(qū)別過(guò)度繪制程度:


①?zèng)]顏色:沒(méi)有過(guò)度繪制,顯示應(yīng)用本來(lái)的顏色
②藍(lán)色:1倍過(guò)度繪制
③綠色:2倍過(guò)度繪制
④淺紅色:3倍過(guò)度繪制
⑤深紅色:4倍過(guò)度繪制及以上

導(dǎo)致過(guò)度繪制的原因很多,例如:

①視圖相互重疊的問(wèn)題
|-- 不必要的背景重疊,如上圖官網(wǎng)介紹
②不合理的xml布局對(duì)繪制的影響
|-- 當(dāng)布局文件的節(jié)點(diǎn)樹(shù)的深度越深,XML 中的標(biāo)簽和屬性設(shè)置越多,對(duì)界面的顯示有巨大影響。一個(gè)界面要顯示出來(lái),第一步會(huì)進(jìn)行解析布局,在 requestLayout 之后還要進(jìn)行一系列的 measure 、 layout 、 draw 操作,若布局文件嵌套過(guò)深、擁有的標(biāo)簽屬性過(guò)于臃腫,每一步的執(zhí)行時(shí)間都會(huì)受到影響,而界面的顯示是進(jìn)行完這些操作后才會(huì)顯示的,所以每一步操作的時(shí)間增長(zhǎng),最終顯示的時(shí)間就會(huì)越長(zhǎng)。

官網(wǎng)給出的合理的頁(yè)面過(guò)度繪制情況

渲染性能

渲染性能往往是掉幀的罪魁禍?zhǔn)?,通過(guò)在 Android 設(shè)備的設(shè)置 APP 的開(kāi)發(fā)者選項(xiàng)里打開(kāi) “ GPU 呈現(xiàn)模式分析 ” 選項(xiàng),可以幫我們有效的分析渲染性能。

追蹤渲染性能,通過(guò)向 dumpsys 傳遞“gfxinfo”命令來(lái)跟蹤相關(guān)的信息

1、幀的聚合信息
這些高級(jí)統(tǒng)計(jì)信息可以較高水平地傳達(dá)應(yīng)用的呈現(xiàn)性能及其在多個(gè)幀之間的穩(wěn)定性

簡(jiǎn)單的時(shí)間幀信息:
|-- 通過(guò)gfxino獲得,Draw、Process、Excute

$ adb shell dumpsys gfxinfo packageName

1、draw代表的是這一幀繪制 Display List 的時(shí)間。通俗來(lái)說(shuō),就是記錄了需要花費(fèi)多長(zhǎng)時(shí)間在屏幕上更新視圖。用代碼語(yǔ)言來(lái)說(shuō),就是執(zhí)行視圖的 onDraw 方法,創(chuàng)建或更新每一個(gè)視圖的 Display List 的時(shí)間。
2、process代表的是這一幀 OpenGL 渲染 Display List 所需要的時(shí)間。通俗來(lái)說(shuō),就是記錄了執(zhí)行視圖繪制的耗時(shí)。用代碼語(yǔ)言來(lái)說(shuō),就是 Android 用 OpenGL ES 的 API 接口進(jìn)行 2D 渲染 Display List 的時(shí)間。
3、excute代表的是這一幀 CPU 等待 GPU 處理的時(shí)間。通俗來(lái)說(shuō),就是 CPU 等待 GPU 發(fā)出接到命令的回復(fù)的等待時(shí)間。用代碼語(yǔ)言來(lái)說(shuō),就是這是一個(gè)阻塞調(diào)用。

精確的幀時(shí)間信息

通過(guò) gfxinfo framestats獲得
|-- 獲取精確時(shí)間幀數(shù)據(jù):

$ adb shell dumpsys gfxinfo packageName framestats
具體的列出在繪制過(guò)程中每一步的時(shí)間,并且所有時(shí)間戳均以納秒為單位
數(shù)據(jù)分析

已獲取到的第二種數(shù)據(jù)為例,先解釋每列數(shù)據(jù)代表的含義
●標(biāo)志

  ?窗口布局發(fā)生變化(例如,應(yīng)用的第一幀或在旋轉(zhuǎn)后)
  ?此外,如果幀的某些值包含無(wú)意義的時(shí)間戳,則也可能跳過(guò)該幀。 例如,如果幀的運(yùn)行速度超過(guò) 60fps,或者如果屏幕上的所有內(nèi)容最終都準(zhǔn)確無(wú)誤,則可能跳過(guò)該幀,這不一定表示應(yīng)用中存在問(wèn)題。
  ?“標(biāo)志”列帶有“0”的行可以通過(guò)從 FRAME_COMPLETED 列中減去 INTENDED_VSYNC 列計(jì)算得出總幀時(shí)間。
  ?該列為非零值的行將被忽略,因?yàn)槠鋵?duì)應(yīng)的幀已被確定為偏離正常性能,其布局和繪制時(shí)間預(yù)計(jì)超過(guò) 16 毫秒。 可能出現(xiàn)這種情況有如下幾個(gè)原因:

●INTENDED_VSYNC

  ?幀的預(yù)期起點(diǎn)。如果此值不同于 VSYNC,則表示 UI 線程中發(fā)生的工作使其無(wú)法及時(shí)響應(yīng)垂直同步信號(hào)。

●VSYNC

  ?所有垂直同步偵聽(tīng)器中使用的時(shí)間值和幀繪圖(Choreographer 幀回調(diào)、動(dòng)畫(huà)、View.getDrawingTime() 等等)
  ?如需進(jìn)一步了解 VSYNC 及其對(duì)應(yīng)用產(chǎn)生的影響,請(qǐng)觀看[了解 VSYNC](https://www.youtube.com/watch?v=1iaHxmfZGGc&list=PLOU2XLYxmsIKEOXh5TwZEv89aofHzNCiu&index=23) 視頻。

●OLDEST_INPUT_EVENT

  ?輸入隊(duì)列中最早輸入事件的時(shí)間戳或 Long.MAX_VALUE(如果幀沒(méi)有輸入事件)。
  ?此值主要用于平臺(tái)工作,對(duì)應(yīng)用開(kāi)發(fā)者的作用有限。

●NEWEST_INPUT_EVENT

  ?輸入隊(duì)列中最新輸入事件的時(shí)間戳或 0(如果幀沒(méi)有輸入事件)。
  ?此值主要用于平臺(tái)工作,對(duì)應(yīng)用開(kāi)發(fā)者的作用有限。
  ?但是,可以通過(guò)查看 (FRAME_COMPLETED - NEWEST_INPUT_EVENT) 大致了解應(yīng)用增加的延遲時(shí)間。

●HANDLE_INPUT_START

  ?將輸入事件分派給應(yīng)用的時(shí)間戳。
  ?通過(guò)觀察此時(shí)間戳與 ANIMATION_START 之間的時(shí)差,可以測(cè)量應(yīng)用處理輸入事件所花的時(shí)間。
  ?如果這個(gè)數(shù)字較高(> 2 毫秒),則表明應(yīng)用處理 View.onTouchEvent() 等輸入事件所花的時(shí)間太長(zhǎng),這意味著此工作需要進(jìn)行優(yōu)化或轉(zhuǎn)交給其他線程。 請(qǐng)注意,有些情況下(例如,啟動(dòng)新Activity或類似活動(dòng)的點(diǎn)擊事件),這個(gè)數(shù)字較大是預(yù)料之中并且可以接受的。

●ANIMATION_START

  ?在 Choreographer 中注冊(cè)的動(dòng)畫(huà)運(yùn)行的時(shí)間戳。
  ?通過(guò)觀察此時(shí)間戳與 PERFORM_TRANVERSALS_START 之間的時(shí)差,可以確定評(píng)估正在運(yùn)行的所有動(dòng)畫(huà)(ObjectAnimator、ViewPropertyAnimator 和通用轉(zhuǎn)換)所需的時(shí)間。
  ?如果這個(gè)數(shù)字較高(> 2 毫秒),請(qǐng)檢查您的應(yīng)用是否編寫了任何自定義動(dòng)畫(huà),或檢查 ObjectAnimator 在對(duì)哪些字段設(shè)置動(dòng)畫(huà)并確保它們適用于動(dòng)畫(huà)。
  ?如需了解有關(guān) Choreographer 的更多信息,請(qǐng)觀看[利弊](https://developers.google.com/events/io/sessions/325418001)視頻。

●PERFORM_TRAVERSALS_START

  ?如果您從此值中扣除 DRAW_START,則可推斷出完成布局和測(cè)量階段所需的時(shí)間(請(qǐng)注意,在滾動(dòng)或動(dòng)畫(huà)期間,您會(huì)希望此時(shí)間接近于零)。
  ?如需了解有關(guān)呈現(xiàn)管道的測(cè)量和布局階段的更多信息,請(qǐng)觀看[失效、布局和性能](https://www.youtube.com/watch?v=we6poP0kw6E&list=PLOU2XLYxmsIKEOXh5TwZEv89aofHzNCiu&index=27)視頻。

●DRAW_START

  ?performTraversals 繪制階段的開(kāi)始時(shí)間。這是記錄任何失效視圖的顯示列表的起點(diǎn)。
  ?此時(shí)間與 SYNC_START 之間的時(shí)差就是對(duì)樹(shù)中的所有失效視圖調(diào)用 View.draw() 所需的時(shí)間。
  ?如需了解有關(guān)繪圖模型的詳細(xì)信息,請(qǐng)參閱[硬件加速](https://developer.android.com/guide/topics/graphics/hardware-accel.html#hardware-model)或[失效、布局和性能](https://www.youtube.com/watch?v=we6poP0kw6E&list=PLOU2XLYxmsIKEOXh5TwZEv89aofHzNCiu&index=27)視頻。

●SYNC_START

  ?繪制同步階段的開(kāi)始時(shí)間。
  ?如果此時(shí)間與 ISSUE_DRAW_COMMANDS_START 之間的時(shí)差較大(約 > 0.4 毫秒),則通常表示繪制了大量必須上傳到 GPU 的新位圖。
  ?如需進(jìn)一步了解同步階段,請(qǐng)觀看 [GPU 呈現(xiàn)模式分析](https://www.youtube.com/watch?v=VzYkVL1n4M8&index=24&list=PLOU2XLYxmsIKEOXh5TwZEv89aofHzNCiu)視頻。

●ISSUE_DRAW_COMMANDS_START

  ?硬件呈現(xiàn)器開(kāi)始向 GPU 發(fā)出繪圖命令的時(shí)間。
  ?此時(shí)間與 FRAME_COMPLETED 之間的時(shí)差讓您可以大致了解應(yīng)用生成的 GPU 工作量。 繪制過(guò)度或呈現(xiàn)效果不佳等問(wèn)題都會(huì)在此顯示出來(lái)。

●SWAP_BUFFERS

  ?調(diào)用 eglSwapBuffers 的時(shí)間,此調(diào)用不屬于平臺(tái)工作,相對(duì)乏味。

●FRAME_COMPLETED

  ?全部完成!處理此幀所花的總時(shí)間可以通過(guò)執(zhí)行 FRAME_COMPLETED - INTENDED_VSYNC 計(jì)算得出。

由于數(shù)據(jù)塊是 CSV 格式的輸出,因此將其粘貼到所選的電子表格工具或使用腳本進(jìn)行收集和解析非常簡(jiǎn)單。我們可以導(dǎo)入Excel進(jìn)行數(shù)據(jù)處理。

利用公式,進(jìn)一步進(jìn)行計(jì)算結(jié)果,并轉(zhuǎn)換單由納秒 -> 毫秒

最后利用Excel生成簡(jiǎn)單直觀的圖表,統(tǒng)計(jì)平均繪制時(shí)間,以及繪制時(shí)間的占比。如下圖表示大部分幀在16ms一下,表示頁(yè)面流暢度“還可以”
具體哪一幀高了,可到對(duì)應(yīng)的數(shù)據(jù)列表中查看,檢查是哪一步導(dǎo)致的。gfxinfo只提供這種“瀏覽方式”,如果還需要進(jìn)一步詳細(xì)的跟蹤,還是需要System Trace的分析。

控制統(tǒng)計(jì)信息收集

時(shí)間

Framestats 和簡(jiǎn)單的幀計(jì)時(shí)均可在極短的時(shí)間內(nèi)(相當(dāng)于約呈現(xiàn) 2 秒)收集數(shù)據(jù)。 因此需要要精確控制此時(shí)間范圍(例如,將數(shù)據(jù)限制于特定動(dòng)畫(huà)),這里可以通過(guò)reset命令,重置所有計(jì)數(shù)器并匯總收集的統(tǒng)計(jì)信息
|-- 清空最近的信息

$ adb shell dumpsys gfxinfo packageName reset
方法:

通過(guò)命令行,輸出固定的滑動(dòng)坐標(biāo),點(diǎn)到點(diǎn),防止人為操作造成誤差。

$ adb shell input swipe 700 2000 700 200

這里只是看滑動(dòng)過(guò)程中的流暢性,然后收集,用pyhton寫了個(gè)渣腳本臨時(shí)處理excel表格。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author:John Hao
# 測(cè)試流暢度平均繪制時(shí)長(zhǎng)的小腳本
# 功能:滑動(dòng)當(dāng)前頁(yè)面兩次,間隔1秒,收集gfxinfo并制表
# titlename:表示要測(cè)試的模塊和最后文件保存的名字
# |-- 收集gfxinfo framestats詳細(xì)幀數(shù)據(jù)信息
# |-- 用第三方模塊openpyxl處理收集到的excel數(shù)據(jù)
# |-- 輸出2秒內(nèi)的120幀每一幀的繪制時(shí)間
# |-- 輸出平均繪制時(shí)間

import time
import sys
import os
import openpyxl
from openpyxl import Workbook
from openpyxl.styles.colors import Color
from openpyxl.chart import LineChart, Reference, Series

titlelist = [' UI 線程中發(fā)生的工作使其無(wú)法及時(shí)響應(yīng)垂直同步信號(hào)','應(yīng)用處理輸入事件所花的時(shí)間( >2 毫秒表示處理輸入事件時(shí)間長(zhǎng))',
                '正在運(yùn)行的所有動(dòng)畫(huà)(ObjectAnimator、ViewPropertyAnimator 和通用轉(zhuǎn)換)所需的時(shí)間',
                '完成布局和測(cè)量階段所需的時(shí)間','對(duì)樹(shù)中的所有視圖調(diào)用 View.draw() 所需的時(shí)間',
                '約 > 0.4 毫秒表示繪制了大量必須上傳到 GPU 的新位圖','GPU 工作量','處理此幀所花的總時(shí)間','達(dá)標(biāo)線']
subtitlelist = ['IntendedVsync','HandleInputStart','AnimationStart','PerformTraversalsStart',
                'DrawStart','SyncStart','IssueDrawCommandsStart','FrameCompleted','Avg']

# 要測(cè)試測(cè)模塊名,最后文件會(huì)以該名稱命名
titlename = "Feed"
print "Starting"

for j in range(1,6):
    time.sleep(1)
    print "開(kāi)始執(zhí)行第" + str(j) + "遍"

    wb = Workbook()
    ws = wb.active
    ws.title = "data"
    valueofwidth = 16
    ws.column_dimensions["A"].width = valueofwidth
    ws.column_dimensions["B"].width = valueofwidth
    ws.column_dimensions["C"].width = valueofwidth
    ws.column_dimensions["D"].width = valueofwidth
    ws.column_dimensions["E"].width = valueofwidth
    ws.column_dimensions["F"].width = valueofwidth
    ws.column_dimensions["G"].width = valueofwidth
    ws.column_dimensions["H"].width = valueofwidth
    ws.column_dimensions["I"].width = valueofwidth
    ws.column_dimensions["J"].width = valueofwidth
    ws.column_dimensions["K"].width = valueofwidth
    ws.column_dimensions["L"].width = valueofwidth
    ws.column_dimensions["M"].width = valueofwidth
    ws.column_dimensions["N"].width = valueofwidth

    # 重置所有計(jì)數(shù)器并匯總收集的統(tǒng)計(jì)信息
    os.popen("adb shell dumpsys gfxinfo PackageName reset")
    print "清理幀信息回到初始狀態(tài)"

    # 模擬滑動(dòng)頁(yè)面操作
    for i in range (1,3):
        print "執(zhí)行滑動(dòng)頁(yè)面操作" + str(i) + "次"
        os.system("adb shell input swipe 700 2000 700 200") 
        time.sleep(1)

    # 過(guò)濾、篩選精確的幀時(shí)間信息
    command = "adb shell dumpsys gfxinfo PackageName framestats | grep -A 120 'Flags'"
    r = os.popen(command)
    info = r.readlines()

    # 數(shù)據(jù)處理中
    print "緩存數(shù)據(jù)中......"
    for line in info:  #按行遍歷
        # line = line.strip('\r\n')
        eachline = line.split(',')
        # 將行寫入Excel表格
        ws.append(eachline)
        # print line

    # 新建sheet用來(lái)統(tǒng)計(jì)數(shù)據(jù)
    resultsheet = wb.create_sheet("result",0)
    resultsheet.column_dimensions["A"].width = valueofwidth
    resultsheet.column_dimensions["B"].width = valueofwidth
    resultsheet.column_dimensions["C"].width = valueofwidth
    resultsheet.column_dimensions["D"].width = valueofwidth
    resultsheet.column_dimensions["E"].width = valueofwidth
    resultsheet.column_dimensions["F"].width = valueofwidth
    resultsheet.column_dimensions["G"].width = valueofwidth
    resultsheet.column_dimensions["H"].width = valueofwidth
    resultsheet.column_dimensions["I"].width = valueofwidth

    # 為結(jié)果頁(yè)添加title說(shuō)明
    resultsheet.append(titlelist)
    resultsheet.append(subtitlelist)
    # resultsheet.RowDimension(height = 5)

    # 填入公式,cell值由納秒轉(zhuǎn)換為毫秒
    for i in range(3,123):
        resultsheet.cell(row = i, column = 1, value = "=data!C" + str(i-1) + "-data!B"+ str(i-1))

    for i in range(3,123):
        value = "=(data!G" + str(i-1) + "-data!F"+ str(i-1)
        resultsheet.cell(row = i, column = 2, value = value + ")/1000000")

    for i in range(3,123):
        value = "=(data!H" + str(i-1) + "-data!G"+ str(i-1)
        resultsheet.cell(row = i, column = 3, value = value + ")/1000000")

    for i in range(3,123):
        value = "=(data!I" + str(i-1) + "-data!G"+ str(i-1)
        resultsheet.cell(row = i, column = 4, value = value + ")/1000000")

    for i in range(3,123):
        value = "=(data!K" + str(i-1) + "-data!I"+ str(i-1)
        resultsheet.cell(row = i, column = 5, value = value + ")/1000000")

    for i in range(3,123):
        value = "=(data!L" + str(i-1) + "-data!K"+ str(i-1)
        resultsheet.cell(row = i, column = 6, value = value + ")/1000000")

    for i in range(3,123):
        value = "=(data!L" + str(i-1) + "-data!K"+ str(i-1)
        resultsheet.cell(row = i, column = 7, value = value + ")/1000000")

    for i in range(3,123):
        value = "=(data!N" + str(i-1) + "-data!B"+ str(i-1)
        resultsheet.cell(row = i, column = 8, value = value + ")/1000000")

    # 插入平均值16ms的列
    for i in range(3,123):
        resultsheet.cell(row = i, column = 9, value = 16)

    # 插入平均Frame值
    resultsheet['J1'] = "平均值ms"
    resultsheet['J2'] = "=AVERAGEA(H3:H122)"

    # 畫(huà)圖準(zhǔn)備
    chart = LineChart()
    chart.title = titlename + str(j)
    # chart.style = 5       #style都很丑,還不如默認(rèn)的
    chart.y_axis.title = 'ms'
    chart.x_axis.title = 'Frame'
    chart.width = 30
    chart.height = 15

    # data選取范圍
    data = Reference(resultsheet, min_col=8, min_row=2, max_col=9, max_row=122)
    chart.add_data(data, titles_from_data=True)

    # 創(chuàng)建圖表,在B3位置插入
    resultsheet.add_chart(chart,"B3")

    #記錄時(shí)間戳作為文件名
    # filename = time.strftime('%Y%m%d_%H%M%S',time.localtime(time.time())) + ".xlsx"
    # wb.save(filename)

    #以執(zhí)行名稱 titlename作為文件名
    filename2 = titlename + str(j) + ".xlsx"
    wb.save(filename2)

    # 數(shù)據(jù)完畢
    print "緩存處理完畢,保存數(shù)據(jù)到本地" + str(filename2)
    time.sleep(3)

Trace View的分析

重要的參數(shù):
? Cpu Time/call
? Calls + Recur
TraceView各項(xiàng)信息及意義:
Name:方法的詳細(xì)信息,包括包名和參數(shù)信息
Incl Cpu Time Cpu:執(zhí)行該方法該方法及其子方法所花費(fèi)的時(shí)間
Incl Cpu Time %:Cpu執(zhí)行該方法該方法及其子方法所花費(fèi)占Cpu總執(zhí)行時(shí)間的百分比
Excl Cpu Time Cpu:執(zhí)行該方法所話費(fèi)的時(shí)間
Excl Cpu Time %:Cpu執(zhí)行該方法所話費(fèi)的時(shí)間占Cpu總時(shí)間的百分比
Incl Real Time:該方法及其子方法執(zhí)行所話費(fèi)的實(shí)際時(shí)間,從執(zhí)行該方法到結(jié)束一共花了多少時(shí)間
Incl Real Time %:上述時(shí)間占總的運(yùn)行時(shí)間的百分比
Excl Real Time %:該方法自身的實(shí)際允許時(shí)間
Excl Real Time:上述時(shí)間占總的允許時(shí)間的百分比
Calls+Recur:調(diào)用次數(shù)+遞歸次數(shù),只在方法中顯示,在子展開(kāi)后的父類和子類方法這一欄被下面的數(shù)據(jù)代替
Calls/Total:調(diào)用次數(shù)和總次數(shù)的占比
Cpu Time/Call Cpu:執(zhí)行時(shí)間和調(diào)用次數(shù)的百分比,代表該函數(shù)消耗cpu的平均時(shí)間
Real Time/Call :實(shí)際時(shí)間于調(diào)用次數(shù)的百分比,該表該函數(shù)平均執(zhí)行時(shí)間

其他方法:

? Animator duration scale

通過(guò)在 Android 設(shè)備的設(shè)置 APP 的開(kāi)發(fā)者選項(xiàng)里打開(kāi) “ 窗口動(dòng)畫(huà)縮放 ” / “ 過(guò)渡動(dòng)畫(huà)縮放 ” / “ 動(dòng)畫(huà)程序時(shí)長(zhǎng)縮放 ”,來(lái)加速或減慢動(dòng)畫(huà)的時(shí)間,以查看加速或減慢狀態(tài)下的動(dòng)畫(huà)是否會(huì)有問(wèn)題。

? StrictMode

通過(guò)在 Android 設(shè)備的設(shè)置 APP 的開(kāi)發(fā)者選項(xiàng)里啟動(dòng) “ 嚴(yán)格模式 ” ,來(lái)查看應(yīng)用哪些操作在主線程上執(zhí)行時(shí)間過(guò)長(zhǎng)。當(dāng)一些操作違背了嚴(yán)格模式時(shí)屏幕的四周邊界會(huì)閃爍紅色,同時(shí)輸出 StrictMode 的相關(guān)信息到 LOGCAT 日志中

Reference:
一些官方參考
?Hierarchy View 官網(wǎng)介紹
https://developer.android.com/studio/profile/hierarchy-viewer-walkthru.html
?Overdraw 官網(wǎng)介紹
https://developer.android.com/studio/profile/dev-options-overdraw.html
?Profiling GPU Rendering 官網(wǎng)介紹
https://developer.android.com/studio/profile/dev-options-rendering.html
?Trace View 官網(wǎng)介紹
https://developer.android.com/studio/profile/traceview-walkthru.html

一些測(cè)試相關(guān)參考
?測(cè)試顯示性能
http://www.jcodecraeer.com/a/anzhuokaifa/developer/2015/0920/3483.html
?Android 編程下的 TraceView 簡(jiǎn)介及其案例實(shí)戰(zhàn)
http://www.cnblogs.com/sunzn/p/3192231.html
?Android界面性能調(diào)優(yōu)手冊(cè)
https://testerhome.com/topics/4304
?正確使用 Android 性能分析工具——TraceView
https://testerhome.com/topics/5049
?【Bugly干貨分享】那些年我們用過(guò)的顯示性能指標(biāo)
http://blog.csdn.net/tencent_bugly/article/details/51354517

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,323評(píng)論 25 708
  • 界面是 Android 應(yīng)用中直接影響用戶體驗(yàn)最關(guān)鍵的部分。如果代碼實(shí)現(xiàn)得不好,界面容易發(fā)生卡頓且導(dǎo)致應(yīng)用占用大量...
    Ten_Minutes閱讀 728評(píng)論 0 9
  • 失眠已經(jīng)成為了我一直以來(lái)的痛病,讓人不能安眠,每當(dāng)夜幕降臨,是想早早入睡的,卻也不得心意,各種煩心瑣事在這個(gè)...
    舊事酒濃意味深長(zhǎng)閱讀 474評(píng)論 0 1
  • 那星辰榮華為誰(shuí)筑成屋脊 縱更深露重只得園外棲身 遙遙天路無(wú)盡 近觀無(wú)計(jì)生存 是福是禍 又何必去問(wèn) 渲墨紙上輕嘆一世...
    暮嵐雪閱讀 309評(píng)論 2 4

友情鏈接更多精彩內(nèi)容