上一篇文章中,我們有提到Activity在屏幕尺寸發生變更時的處理方式,總共有兩種: 1. 重啟APP以適應屏幕改變; 2. 手動處理數據,避免APP重啟。 同樣,這兩種方式也同時適用於改變屏幕方向、更改系統語言、甚至輸入法等等。 因此,本文也同樣 適用於改變屏幕方向等情況的處理。 或許你會有疑問: ...
上一篇文章中,我們有提到Activity在屏幕尺寸發生變更時的處理方式,總共有兩種:
- 重啟APP以適應屏幕改變;
- 手動處理數據,避免APP重啟。
同樣,這兩種方式也同時適用於改變屏幕方向、更改系統語言、甚至輸入法等等。
因此,本文也同樣適用於改變屏幕方向等情況的處理。
或許你會有疑問:我們該如何選擇合適的處理方式呢?
我給你的答案是:選擇最合適的。
這麼說好像跟沒說一樣,別急,給大家舉個例子就明白了:
比如更改屏幕方向,由豎屏轉換為橫屏,如果我們只有一套佈局,符合按比例縮放仍然顯示正常的話,我們大可以選擇第2種處理方案。但是如果我們的橫豎屏佈局是不同的,比如系統中的“設置”應用,那麼我們選擇第2種處理方案就是不合適的。
下圖:
這是一個典型的橫豎屏分別採用不同佈局的例子。
我們確定要採取那種解決方案後,接下來很可能要面對另一個問題,就是性能瓶頸。
根據前一篇文章的實驗結果,在發生橫豎屏切換的時候,Activity的生命周期通常會按照如下順序依次執行:
D/MainActivity: onPause
D/MainActivity: onSaveInstanceState
D/MainActivity: onStop
D/MainActivity: onDestroy
D/MainActivity: onCreate
D/MainActivity: onStart
D/MainActivity: onRestoreInstanceState
D/MainActivity: onResume
如果我們在生命周期中做了一些繁重的工作,那麼整個Activity在重啟的過程中就會很慢。
要解決這個問題,首先我們要找Fragment幫忙,因為Bundle並不是用來傳遞大型對象的,而且這個對象還需要序列化和反序列化,如此執行起來就更慢了。
當然,如果你只是保存一些整型或者字元串的話,單純使用Bundle而不藉助Fragment也是可以的,但是這樣的場景在實際開發中並不常見。
要藉助Fragment來中轉對象,我們採用下麵三步走的方式:
- 在Fragment類中調用 setRetainInstance(true);
- 在Activity銷毀時向Fragment類存入數據;
- 在Activity重建後根據Tag檢索Fragment,並取出之前存入的數據。
下麵用具體的代碼片來演示:
首先來看Fragment類:
public class TestFragment extends Fragment {
private MyData data;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
public void setData(MyData data) {
this.data = data;
}
public MyData getData() {
return data;
}
}
我們再來看Activity類:
public class MyActivity extends Activity {
private TestFragment mTestFragment ;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentManager fm = getFragmentManager();
mTestFragment = (TestFragment)fm.findFragmentByTag(“test”);
if (retainedFragment == null) {
mTestFragment = new TestFragment ();
fm.beginTransaction().add(mTestFragment, “test”).commit();
mTestFragment.setData(restoreData());
}
}
@Override
public void onDestroy() {
super.onDestroy();
mTestFragment.setData(saveData());
}
}
這裡還要特別註意一點:在中轉對象數據時,不要傳入與Activity緊密相關的對象,比如View,否則會造成記憶體泄漏。
至此,就完成了對重啟Activity方案的性能優化。