Android面試題-與效能優化相關面試題六
本文配套視訊
原始碼分析相關面試題
與XMPP相關面試題
與效能優化相關面試題
與登入相關面試題
與開發相關面試題
與人事相關面試題
Android效能優化之App應用啟動分析與優化
App啟動方式
通常來說, 一個App啟動也會分如下二中不同的狀態:
.1)冷啟動
當啟動應用時,後臺沒有該應用的程序,這時系統會重新建立一個新的程序分配給該應用,這個啟動方式就是冷啟動。冷啟動因為系統會重新建立一個新的程序分配給它,所以會先建立和初始化Application類,再建立和初始化MainActivity類(包括一系列的測量、佈局、繪製),最後顯示在介面上。
2.)熱啟動
當啟動應用時,後臺已有該應用的程序(例:按back鍵、home鍵,應用雖然會退出,但是該應用的程序是依然會保留在後臺,可進入任務列表檢視),所以在已有程序的情況下,這種啟動會從已有的程序中來啟動應用,這個方式叫熱啟動。熱啟動因為會從已有的程序中來啟動,所以熱啟動就不會走Application這步了,而是直接走MainActivity(包括一系列的測量、佈局、繪製),所以熱啟動的過程只需要建立和初始化一個MainActivity就行了,而不必建立和初始化Application,因為一個應用從新程序的建立到程序的銷燬,Application只會初始化一次。
啟動時間的測量
關於Activity啟動時間的定義
對於Activity來說,啟動時,首先執行的是onCreate()、onStart()、onResume()這些生命週期函式,但即使這些生命週期方法回撥結束了,應用也不算已經完全啟動,還需要等View樹全部構建完畢,一般認為,setContentView中的View全部顯示結束了,算作是應用完全啟動了。
Display Time
從API19之後,Android在系統Log中增加了Display的Log資訊,通過過濾ActivityManager以及Display這兩個關鍵字,可以找到系統中的這個Log:
$ adb logcat | grep “ActivityManager”
ActivityManager: Displayed com.example.launcher/.LauncherActivity: +999ms
抓到的Log如圖所示:
那麼這個時間,實際上是Activity啟動,到Layout全部顯示的過程,但是要注意,這裡並不包括資料的載入,因為很多App在載入時會使用懶載入模式,即資料拉取後,再重新整理預設的UI。
基於上面的啟動流程我們儘量做到如下幾點
1) Application的建立過程中儘量少的進行耗時操作
2) 首屏Activity的渲染
當前冷啟動效果:
Application
Application是程式的主入口,特別是很多第三方SDK都會需要在Application的onCreate裡面做很多初始化操作,一般來說我們可以將這些初始化放在一個單獨的執行緒中處理, 為了方便今後管理,
優化的方法,無非是通過以下幾個方面:
1)非同步初始化
2)後臺任務
3)介面預載入
非同步初始化
這個很簡單,就是讓App在onCreate裡面儘可能的少做事情,而利用手機的多核特性,儘可能的利用多執行緒,例如一些第三方框架的初始化,如果能放執行緒,就儘量的放入執行緒中,最簡單的,你可以直接new Thread(),當然,你也可以通過公共的執行緒池來進行非同步的初始化工作,這個是最能夠壓縮啟動時間的方式
後臺任務
因為這個App一般會整合很多三方SDK等服務, 所以Application的onCreate有很多第三方平臺的初始化工作…
Application程式碼如下:
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
LitePal.initialize(this.getApplicationContext());
}
}
使用IntentService不同於Service, 它是工作在後臺執行緒的.
IntentService程式碼如下:
public class InitializeService extends IntentService {
private static final String ACTION_INIT_WHEN_APP_CREATE = "com.maweiqi";
public InitializeService(String name) {
super(name);
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_INIT_WHEN_APP_CREATE.equals(action)) {
performInit();
}
}
}
private void performInit() {
LitePal.initialize(this.getApplicationContext());
}
public static void start(Context context) {
Intent intent = new Intent(context, InitializeService.class);
intent.setAction(ACTION_INIT_WHEN_APP_CREATE);
context.startService(intent);
}
}
MyApp的onCreate改成:
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
InitializeService.start(this);
}
}
最終的效果
介面預載入
當系統載入一個Activity的時候,onCreate()是一個耗時過程,那麼在這個過程中,系統為了讓使用者能有一個比較好的體驗,實際上會先繪製一些初始介面,類似於PlaceHolder。
系統首先會讀取當前Activity的Theme,然後根據Theme中的配置來繪製,當Activity載入完畢後,才會替換為真正的介面。所以,Google官方提供的解決方案,就是通過android:windowBackground屬性,來進行載入前的配置,同時,這裡不僅可以配置顏色,還能配置圖片,例如,我們可以使用一個layer-list來作為android:windowBackground要顯示的圖:
在drawable資料夾下面 , 做一個logo_splash的背景:
start_window.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 底層白色 -->
<item android:drawable="@color/white" />
<!-- 頂層Logo居中 -->
<item>
<bitmap
android:gravity="center"
android:src="@drawable/ic_github" />
</item>
</layer-list>
在style裡面弄一個主題:
<style name="StartStyle" parent="AppTheme">
<item name="android:windowBackground">@drawable/start_window</item>
</style>
在清單檔案裡面給Activity指定需要預載入的Style:
<activity android:name=".MainActivity" android:theme="@style/StartStyle">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
activity程式碼如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppTheme);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
首屏Activity的渲染
Android系統每隔16ms會發出VSYNC訊號重繪我們的介面(Activity).
為什麼是16ms, 因為Android設定的重新整理率是60FPS(Frame Per Second), 也就是每秒60幀的重新整理率, 約合16ms重新整理一次.就像是這樣的:
這就意味著, 我們需要在16ms內完成下一次要重新整理的介面的相關運算, 以便介面重新整理更新. 然而, 如果我們無法在16ms內完成此次運算會怎樣呢?
例如, 假設我們更新螢幕的背景圖片, 需要24ms來做這次運算. 當系統在第一個16ms時重新整理介面, 然而我們的運算還沒有結束, 無法繪出圖片. 當系統隔16ms再發一次VSYNC資訊重繪介面時, 使用者才會看到更新後的圖片. 也就是說使用者是32ms後看到了這次重新整理(注意, 並不是24ms). 這就是傳說中的丟幀(dropped frame):
丟幀給使用者的感覺就是卡頓, 而且如果運算過於複雜, 丟幀會更多, 導致介面常常處於停滯狀態, 卡到爆.
- 歡迎關注微信公眾號,長期推薦技術文章和技術視訊