最近有關摺疊屏產品的新聞層出不窮,各家手機廠商也分別慢慢地亮出了自家的產品。然而市場上的一些APP仍然沒有很好地適配這樣的設備,顯示不正常和應用重啟的狀況時有發生。因此,我會用接下來的幾篇文章來點出有關摺疊屏開發中的一些需要註意的地方。 今天我們先來說一下 生命周期 ,這是廣大開發者特別需要註意的一 ...
最近有關摺疊屏產品的新聞層出不窮,各家手機廠商也分別慢慢地亮出了自家的產品。然而市場上的一些APP仍然沒有很好地適配這樣的設備,顯示不正常和應用重啟的狀況時有發生。因此,我會用接下來的幾篇文章來點出有關摺疊屏開發中的一些需要註意的地方。
今天我們先來說一下生命周期,這是廣大開發者特別需要註意的一點。
首先我們來看一下測試代碼:
public class MainActivity extends AppCompatActivity {
private final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate");
}
@Override
protected void onStart() {
super.onStart();
Log.d(TAG, "onStart");
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume");
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(TAG, "onRestart");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(TAG, "onSaveInstanceState");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d(TAG, "onRestoreInstanceState");
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.d(TAG, "onConfigurationChanged");
}
}
我在每一個生命周期和恢復現場的回調方法中都加了Logcat輸出,我們來看一下切換屏幕時APP的具體表現。
2019-01-30 11:19:00.216 30205-30205/com.example.helloworld D/MainActivity: onPause
2019-01-30 11:19:00.221 30205-30205/com.example.helloworld D/MainActivity: onSaveInstanceState
2019-01-30 11:19:00.227 30205-30205/com.example.helloworld D/MainActivity: onStop
2019-01-30 11:19:00.228 30205-30205/com.example.helloworld D/MainActivity: onDestroy
2019-01-30 11:19:00.325 30205-30205/com.example.helloworld D/MainActivity: onCreate
2019-01-30 11:19:00.326 30205-30205/com.example.helloworld D/MainActivity: hashcode is 89642980
2019-01-30 11:19:00.327 30205-30205/com.example.helloworld D/MainActivity: onStart
2019-01-30 11:19:00.328 30205-30205/com.example.helloworld D/MainActivity: onRestoreInstanceState
2019-01-30 11:19:00.331 30205-30205/com.example.helloworld D/MainActivity: onResume
我們可以看到,預設情形下,Activity在屏幕尺寸發生改變的時候也隨之重啟了。 和改變屏幕Orientation的行為有幾分相像。
此時我們面臨兩個選擇:
- 重啟APP以適應屏幕改變;
- 手動處理數據,避免APP重啟。
對於第一種情況,我們一般在回調onSaveInstanceState()方法中保存數據,併在onCreate()或onRestoreInstanceState()回調方法中取回保存的數據用於恢復現場。
然而,並非在所有情況下都需要完整地重啟APP來適應屏幕改變,和改變屏幕方向一樣,我們只需要在Androidmanifest.xml中相應的Activity聲明中加入相應的屬性值即可。此處,需要添加:
android:configChanges="screenSize|smallestScreenSize|screenLayout"
添加好之後再次運行APP並反覆改變屏幕大小,此時的生命周期回調順序變為:
2019-01-30 11:13:02.217 29276-29276/com.example.helloworld D/MainActivity: onCreate
2019-01-30 11:13:02.219 29276-29276/com.example.helloworld D/MainActivity: onStart
2019-01-30 11:13:02.223 29276-29276/com.example.helloworld D/MainActivity: onResume
2019-01-30 11:13:05.289 29276-29276/com.example.helloworld D/MainActivity: onConfigurationChanged
可見,此時Activity並沒有銷毀重建,而是只回調了onConfigurationChanged()方法。在某些情況下,可用此辦法避免APP重啟。
那麼,上述三個屬性值各代表什麼意思呢,詳見下表:
屬性值 | 含義 |
---|---|
screenSize | 當前可用屏幕尺寸發生了變化。它表示當前可用尺寸相對於當前縱橫比的變化,因此會在用戶在橫向與縱向之間切換時發生變化。 不過,如果您的應用面向 API 級別 12 或更低級別,則 Activity 始終會自行處理此配置變更(即便是在 Android 3.2 或更高版本的設備上運行,此配置變更也不會重新啟動 Activity)。 |
smallestScreenSize | 物理屏幕尺寸發生了變化。它表示與方向無關的尺寸變化,因此只有在實際物理屏幕尺寸發生變化(如切換到外部顯示器)時才會變化。 對此配置的變更對應於smallestWidth 配置的變化。 不過,如果您的應用面向 API 級別 12 或更低級別,則 Activity 始終會自行處理此配置變更(即便是在 Android 3.2 或更高版本的設備上運行,此配置變更也不會重新啟動 Activity)。 |
screenLayout | 屏幕佈局發生了變化 — 這可能是由激活了其他顯示方式所致。 |
註:上表摘自 https://developer.android.com/guide/topics/manifest/activity-element
如此,我們便處理完了對於摺疊屏切換屏幕的優化。