一、概述
使用Systrace
需要開發者對於整個渲染的原理有較深的理解,而TraceView
則更為直觀,你可以通過它來分析在一段時間應用內各個執行緒的執行情況,它會幫你計算出每個方法的具體耗時,這樣我們就可以瞭解到方法執行的效率,定位到當前效能的瓶頸在哪,從而考慮將一些耗時的操作放在子執行緒中進行,或者延後執行來優化應用的啟動速度和解決卡頓問題。
和之前一樣,我們分幾個部分介紹它:
- 獲取
TraceView
的分析報表 - 分析報表的格式
- 具體案例
二、獲取*.trace
報表
- 第一步:點選
Android Studio
中的Tools/Android/Android Device Monitor
,開啟除錯介面。 - 第二步:如下面截圖所示,選中要分析的應用包名,點選
Start Method Profiling
按鈕,之後就會開始跟蹤: - 第三步:進入應用內進行操作,操作完畢後,再次點選上面的按鈕
Stop Method Profiling
,等待一會,就會在右邊的視窗生成分析的報表,將滑鼠上移到紅框的檔名處,可以看到儲存的位置,我們可以把它儲存起來以便之後分析跟蹤問題:
三、分析*.trace
報表
獲取完報表之後,我們就可以通過它來分析,這個區域分為三個部分:
- 紅色區域:列出了執行的各個執行緒。
- 藍色區域:執行緒在一段時間內的執行情況,我們點選有顏色的地方,就可以定位到具體做了哪些操作。
- 紫色區域:方法呼叫的具體情況。
前面兩個區域都比較好理解,我們主要看一下紫色區域的每一列具體的含義:
上面的表格中,一部分單位是百分比,另一部分是ms
,要注意區別,除此之外,有兩點需要解釋一下:
Incl
和Excl
的概念 關於Incl
和Excl
的概念可以用下面這段程式碼來表示:
public static void inclExcl(Context context) { //這個函式的執行時間為 Incl Real Time
//假如這裡沒有呼叫任何函式,那麼這裡的執行時間就是:Excl Real Time
writeSomething(context, 1000); //這裡的執行時間是:Incl Real Time - Excl Real Time
}
複製程式碼
Cpu Time
和Real Time
的區別Real Time
表示的是一個函式從開始到執行時候所佔用的時間,而CPU Time
則表示CPU
執行這段函式所耗費的時間。 舉個例子,假如我們一個函式doSomething()
,CPU
執行它首先花了time1
的時間,之後CPU
被分配用去執行別的函式花了time2
,執行完之後繼續回來執行doSomething()
,花了time3
的時間把它執行完,那麼doSomething()
的Real Time
就等於time1 + time2 + time3
,而Cpu Time
則等於time1 + time3
。
我們可以通過點選具體的列進行排序,在平時的分析中,我們主要關注一下:
-
CPU Time / Call
較高 這一列表示函式的單個執行時間較長,這裡往往是可以優化的點: -
分析該函式的實現方式,能夠用其它的方法來實現,從而減少函式的執行時間
-
分析該函式所執行的執行緒,如果可以那麼把它放到子執行緒中執行
-
分析該函式所呼叫的時機,避免在應用啟動,或者做動畫的過程中執行它,否則會導致啟動速度變慢和介面卡頓。
-
CPU Time
較高,但CPU Time / Call
不高 這一列表示函式的單個執行時長不長,但呼叫的次數很多,這同樣是可以優化的點,需要看一下是否有必要在每個地方都呼叫它,能否進行延後操作,統計到一個地方執行。 -
和
Android
相關的某些函式的Real Time
: 由於我們的介面需要等到onCreate
、onResume
等函式執行完之後,才會真正的顯示出來,因此,我們需要保證它們能夠儘快地執行完,也就是它的Incl Real Time
儘可能地短: 例如下面兩點是最基本的: -
onCreate
: -
onResume
:
四、具體案例
我們分析一下在啟動過程中,由於佈局複雜或者耗時操作導致的問題: 首先我們看一下正常的情況:
callActivityOnCreate
部分耗時為6.180ms
callActivityOnResume
耗時為1.219ms
4.1 佈局層次過於複雜導致的問題
我們修改Activity
的根佈局:
<FrameLayout
android:background="@android:color/black"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:background="@android:drawable/screen_background_dark"
android:layout_width="match_parent"
android:layout_height="500dp">
<FrameLayout
android:background="@android:drawable/star_big_off"
android:layout_width="match_parent"
android:layout_height="400dp">
<FrameLayout
android:background="@android:drawable/bottom_bar"
android:layout_width="match_parent"
android:layout_height="300dp">
<FrameLayout
android:background="@android:color/holo_blue_bright"
android:layout_width="match_parent"
android:layout_height="200dp">
</FrameLayout>
</FrameLayout>
</FrameLayout>
</FrameLayout>
</FrameLayout>
複製程式碼
再次抓取之後,看一下onCreate
的時間,發現耗時增加到17ms
:
4.2 在啟動過程中進行耗時的操作
首先把佈局恢復成沒有問題的狀態,然後在onCreate
和onResume
方法中增加不同的IO
操作:
public class TraceViewActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_trace_view);
TraceViewOperation.writeOnActivityOnCreate(this, 1000);
}
@Override
protected void onResume() {
super.onResume();
TraceViewOperation.writeOnActivityOnResume(this, 1000);
}
}
複製程式碼
其中onCreate
在主執行緒中進行,而onResume
裡面則另起了一個執行緒:
public class TraceViewOperation {
public static void writeOnActivityOnCreate(Context context, int count) {
writeSomething(context, count);
}
public static void writeOnActivityOnResume(final Context context, final int count) {
new Thread() {
@Override
public void run() {
super.run();
writeSomething(context, count);
}
}.start();
}
}
複製程式碼
onCreate
耗時: 和上面類似,點進去看耗時的方法,正是由於我們在前面進行IO
操作引起的:onResume
耗時: 可以看到,由於我們是另起了一個執行緒進行操作,因此,並不會佔用它的執行時間。
五、小結
通過TraceView
,我們可以瞭解到某些關鍵函式上的執行時間,正如前面第三點談到的,根據不同的情況進行分析和優化,將會有效地提高應用的啟動速度,避免出現卡頓現象。
更多文章,歡迎訪問我的 Android 知識梳理系列:
- Android 知識梳理目錄:www.jianshu.com/p/fd82d1899…
- 個人主頁:lizejun.cn
- 個人知識總結目錄:lizejun.cn/categories/