Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 處理運行時變更---Develop ---API Guides ---App Resources

處理運行時變更---Develop ---API Guides ---App Resources

編輯:關於Android編程

有些設備配置可能會在運行時發生變化(例如屏幕方向、鍵盤可用性及語言)。 發生這種變化時,Android 會重啟正在運行的Activity(先後調用onDestroy()和onCreate())。重啟行為旨在通過利用與新設備配置匹配的備用資源自動重新加載您的應用,來幫助它適應新配置。

要妥善處理重啟行為,Activity 必須通過常規的Activity 生命周期恢復其以前的狀態,在 Activity 生命周期中,Android 會在銷毀 Activity 之前調用onSaveInstanceState(),以便您保存有關應用狀態的數據。 然後,您可以在onCreate()或onRestoreInstanceState()期間恢復 Activity 狀態。

要測試應用能否在保持應用狀態完好的情況下自行重啟,您應該在應用中執行各種任務時調用配置變更(例如,更改屏幕方向)。 您的應用應該能夠在不丟失用戶數據或狀態的情況下隨時重啟,以便處理如下事件:配置發生變化,或者用戶收到來電並在應用進程被銷毀很久之後返回到應用。 要了解如何恢復 Activity 狀態,請閱讀Activity 生命周期。

但是,您可能會遇到這種情況:重啟應用並恢復大量數據不僅成本高昂,而且給用戶留下糟糕的使用體驗。 在這種情況下,您有兩個其他選擇:

在配置變更期間保留對象

允許 Activity 在配置變更時重啟,但是要將有狀態對象傳遞給 Activity 的新實例。

自行處理配置變更

阻止系統在某些配置變更期間重啟 Activity,但要在配置確實發生變化時接收回調,這樣,您就能夠根據需要手動更新 Activity。

在配置變更期間保留對象


如果重啟 Activity 需要恢復大量數據、重新建立網絡連接或執行其他密集操作,那麼因配置變更而引起的完全重啟可能會給用戶留下應用運行緩慢的體驗。 此外,依靠系統通過onSaveInstanceState()回調為您保存的Bundle,可能無法完全恢復 Activity 狀態,因為它 並非設計用於攜帶大型對象(例如位圖),而且其中的數據必須先序列化,再進行反序列化, 這可能會消耗大量內存並使得配置變更速度緩慢。在這種情況下,如果 Activity 因配置變更而重啟,則可通過保留Fragment來減輕重新初始化 Activity 的負擔。此片段可能包含對您要保留的有狀態對象的引用。

當 Android 系統因配置變更而關閉 Activity 時,不會銷毀您已標記為要保留的 Activity 的片段。您可以將此類片段添加到 Activity 以保留有狀態的對象。

要在運行時配置變更期間將有狀態的對象保留在片段中,請執行以下操作:

  1. 擴展Fragment類並聲明對有狀態對象的引用。
  2. 在創建片段後調用setRetainInstance(boolean)。
  3. 將片段添加到 Activity。
  4. 重啟 Activity 後,使用FragmentManager檢索片段。

例如,按如下所示定義片段:

public class RetainedFragment extends Fragment {

  // data object we want to retain
  private MyDataObject data;

  // this method is only called once for this fragment
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // retain this fragment
    setRetainInstance(true);
  }

  public void setData(MyDataObject data) {
    this.data = data;
  }

  public MyDataObject getData() {
    return data;
  }
}

注意:盡管您可以存儲任何對象,但是切勿傳遞與Activity綁定的對象,例如,Drawable、Adapter、View或其他任何與Context關聯的對象。否則,它將洩漏原始 Activity 實例的所有視圖和資源。 (洩漏資源意味著應用將繼續持有這些資源,但是無法對其進行垃圾回收,因此可能會丟失大量內存。)

然後,使用FragmentManager將片段添加到 Activity。在運行時配置變更期間再次啟動 Activity 時,您可以獲得片段中的數據對象。 例如,按如下所示定義 Activity:

public class MyActivity extends Activity {

  private RetainedFragment dataFragment;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // find the retained fragment on activity restarts
    FragmentManager fm = getFragmentManager();
    dataFragment = (DataFragment) fm.findFragmentByTag(“data”);

    // create the fragment and data the first time
    if (dataFragment == null) {
      // add the fragment
      dataFragment = new DataFragment();
      fm.beginTransaction().add(dataFragment, “data”).commit();
      // load the data from the web
      dataFragment.setData(loadMyData());
    }

    // the data is available in dataFragment.getData()
    ...
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    // store the data in the fragment
    dataFragment.setData(collectMyLoadedData());
  }
}

在此示例中,onCreate()添加了一個片段或恢復了對它的引用。此外,onCreate()還將有狀態的對象存儲在片段實例內部。onDestroy()對所保留的片段實例內的有狀態對象進行更新。

自行處理配置變更


如果應用在特定配置變更期間無需更新資源,並且因性能限制您需要盡量避免重啟,則可聲明 Activity 將自行處理配置變更,這樣可以阻止系統重啟 Activity。

注:自行處理配置變更可能導致備用資源的使用更為困難,因為系統不會為您自動應用這些資源。 只能在您必須避免Activity因配置變更而重啟這一萬般無奈的情況下,才考慮采用自行處理配置變更這種方法,而且對於大多數應用並不建議使用此方法。

要聲明由 Activity 處理配置變更,請在清單文件中編輯相應的元素,以包含android:configChanges屬性以及代表要處理的配置的值。android:configChanges屬性的文檔中列出了該屬性的可能值(最常用的值包括"orientation"和"keyboardHidden",分別用於避免因屏幕方向和可用鍵盤改變而導致重啟)。您可以在該屬性中聲明多個配置值,方法是用管道|字符分隔這些配置值。

例如,以下清單文件代碼聲明的 Activity 可同時處理屏幕方向變更和鍵盤可用性變更:

現在,當其中一個配置發生變化時,MyActivity不會重啟。相反,MyActivity會收到對onConfigurationChanged()的調用。向此方法傳遞Configuration對象指定新設備配置。您可以通過讀取Configuration中的字段,確定新配置,然後通過更新界面中使用的資源進行適當的更改。調用此方法時,Activity 的Resources對象會相應地進行更新,以根據新配置返回資源,這樣,您就能夠在系統不重啟 Activity 的情況下輕松重置 UI 的元素。

注意:從 Android 3.2(API 級別 13)開始,當設備在縱向和橫向之間切換時,“屏幕尺寸”也會發生變化。因此,在開發針對 API 級別 13 或更高版本系統的應用時,若要避免由於設備方向改變而導致運行時重啟(正如minSdkVersiontargetSdkVersion屬性中所聲明),則除了"orientation"值以外,您還必須添加"screenSize"值。即,您必須聲明android:configChanges="orientation|screenSize"。但是,如果您的應用是面向 API 級別 12 或更低版本的系統,則 Activity 始終會自行處理此配置變更(即便是在 Android 3.2 或更高版本的設備上運行,此配置變更也不會重啟 Activity)。

例如,以下onConfigurationChanged()實現 檢查當前設備方向:

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);

  // Checks the orientation of the screen
  if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
    Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
  } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
    Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
  }
}

Configuration對象代表所有當前配置,而不僅僅是已經變更的配置。大多數時候,您並不在意配置具體發生了哪些變更,而且您可以輕松地重新分配所有資源,為您正在處理的配置提供備用資源。 例如,由於Resources對象現已更新,因此您可以通過setImageResource()重置任何ImageView,並且使用適合於新配置的資源(如提供資源中所述)。

請注意,Configuration字段中的值是與Configuration類中的特定常量匹配的整型數。有關要對每個字段使用哪些常量的文檔,請參閱Configuration參考文檔中的相應字段。

請謹記:在聲明由 Activity 處理配置變更時,您有責任重置要為其提供備用資源的所有元素。 如果您聲明由 Activity 處理方向變更,而且有些圖像應該在橫向和縱向之間切換,則必須在onConfigurationChanged()期間將每個資源重新分配給每個元素。

如果無需基於這些配置變更更新應用,則可不用實現onConfigurationChanged()。在這種情況下,仍將使用在配置變更之前用到的所有資源,只是您無需重啟 Activity。 但是,應用應該始終能夠在保持之前狀態完好的情況下關閉和重啟,因此您不得試圖通過此方法來逃避在正常 Activity 生命周期期間保持您的應用狀態。 這不僅僅是因為還存在其他一些無法禁止重啟應用的配置變更,還因為有些事件必須由您處理,例如用戶離開應用,而在用戶返回應用之前該應用已被銷毀。

如需了解有關您可以在 Activity 中處理哪些配置變更的詳細信息,請參閱android:configChanges文檔和Configuration類。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved