應用除了有內存佔用、內存泄露、內存抖動等看不見的性能問題外,還有很多看得見的性能問題,比如進入界面慢、點擊反應慢、頁面卡頓等等,這些看得見的體驗問題會嚴重影響用戶使用APP心情,但用戶的情緒又無法通過異常採集、數據分析來發現,儘早優化APP的性能體驗問題非常重要,會在一定程度上提升用戶的留存率。
本文結合最近一段時間對項目中APP各界面進入速度的優化,總結一下進入界面慢的優化方案。先從Activity的生命週期說起,從一個界面FirstActivity跳轉到另外一個界面SecondActivity,應用必須在走完FirstActivity的onPause方法後纔會跑SecondActivity的onCreate方法,FirstActivity的onStop和onDestory方法不會影響到進入SecondActivity的速度。如果我們要優化從FirstActivity跳轉到SecondActivity的速度,需要從FristActivity的onPause和SecondActivity的onCreate、onStart和onResume方法入手。onStart方法通常乾的事情比較少,頁面之間跳轉慢主要是因爲在FirstActivity的onPause和SecondActivity的onCreate、onResume方法耗時導致,這個過程需要執行的操作主要有:
-
保存FirstActivity界面中的一些狀態;
-
加載SecondActivity的佈局;
-
初始化SecondActivity。
針對上面的分析我們可以從如下四個方面入手:
-
耗時任務異步處理;
-
佈局文件優化;
-
不可見視圖需要時加載;
-
應用內慎用多進程。
優化實踐
耗時任務異步處理
除了Android明令禁止在UI線程中執行網絡操作外,還有一些耗時的操作也不能在UI線程中執行,比如IO操作、耗時較長的邏輯操作(比如算法),在Android中可以通過如下幾種方式來實現異步任務:
-
AsyncTask
-
Thread
-
Timer,TimerTask
-
Handler
如果是在執行異步任務後需要更新界面,優先考慮使用AsyncTask和Handler,它們提供了刷新UI的方案;如果是定時任務可以考慮使用Handler和Timer,TimerTask;如果是使用Thread和Timer,TimerTask,更新UI時可以通過執行當前Activity的runOnUiThread方法實現更新UI操作。
佈局文件優化 ViewStub
在優化過程中發現有的界面光是加載佈局就需要500ms左右,再加上界面的初始化和上一個界面的狀態保存操作,頁面跳轉時會有嚴重的遲滯感,對於佈局文件的優化網上有很多有價值的文章,最重要的兩條是:
-
佈局文件不要嵌套太深;
-
對於不需要進入界面就需要顯示的視圖,強烈建議使用ViewStub。
佈局文件嵌套太深標示着需要更多次的佈局、測量和繪製,會導致耗時更多,這個可以使用android自帶的“hierarchyviewer”查看,邊優化邊看效果;但有時候即使佈局足夠扁平,加載佈局文件時還是會比較耗時,因爲佈局文件中的視圖太多了,此時對於不需要進入界面就需要顯示的視圖,可以使用ViewStub來延遲加載,比如加載的進度條、特定狀態下出現的倒計時和動畫等,ViewStub的使用方式如下:
/**
* 在需要使用下載進度條的地方調用該方法加載下載進度條的佈局
*/
private void initDownloadProgress() {
if(null == mDownloadViewStub){
mDownloadViewStub = (ViewStub)findViewById(R.id.downProgressViewStubId);
View view = mDownloadViewStub.inflate();
mDownloadProgressLayout = (RelativeLayout) view.findViewById(R.id.progressBackLayoutId);
mDownLoadProgressBar = (ArrowProgressBar) view.findViewById(R.id.arrowProgressBarId);
mDownloadProgressLayout.setVisibility(View.GONE);
mDownloadProgressLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
}
}
不可見視圖需要時加載
除了佈局文件的優化外,代碼中不需要立即顯示的視圖和動畫都做成延遲加載,比如AnimationDrawable、TypedArray數組、Typeface、addView等,值得一提的是,初始化AnimationDrawable、TypedArray數組和Typeface會很耗時,並且AnimationDrawable特別耗內存,如果不是進入界面就需要使用,強烈建議在需要使用的地方再初始化,分開初始化可以大大減小頁面初始化的耗時。
應用內慎用多進程
從FirstActivity跳轉到SecondActivity,如果這兩個界面不屬於同一個進程,首次跳轉的時候會創建一個新的進程,創建進程是比較耗時的,比跳轉到同一進程內的新頁面耗時更多,如果不是必須要在應用內使用多進程,強烈建議不要在應用內使用多進程。
總結
性能優化是一個持續的過程,界面跳轉效率只是一個性能指標,更快地跳轉對於用戶來說有着更好地體驗,優化界面跳轉速度的步驟如下:
-
打印執行每一段代碼執行需要的時間;
-
找到耗時較多的代碼段,可能是setContentView,也有可能是在UI線程中的其它耗時操作;
-
根據耗時的代碼段找解決辦法;
-
優化後運行看效果。
特別說明:
-
初始化AnimationDrawable、TypedArray數組和Typeface會很耗時,並且AnimationDrawable特別耗內存,一定要注意他們的初始化時機;
-
不要迷信網上的一些優化技巧,一定要結合親身實踐,看數據說話;
-
只要認真分析,很多地方都會有優化空間,將優化的經驗總結出來,並運用到後續的開發中;
-
優化APP的性能問題在一定程度上能夠提高用戶的留存率,是一件很有價值的事情。