Android中文API
我的世界手机版火傀儡制作教程

處理運行時變更

時間:2017-03-11 11:04來源: 作者: 點擊:
有些設備配置可能會在運行時發生變化(例如屏幕方向、鍵盤可用性及語言)。 發生這種變化時,Android 會重啟正在運行的 Activity(先后調用 onDestroy() 和 onCreate())。重啟行為旨在通過利用與新

我的世界手机版火傀儡制作教程 www.cklgw.icu 有些設備配置可能會在運行時發生變化(例如屏幕方向、鍵盤可用性及語言)。 發生這種變化時,Android 會重啟正在運行的 Activity(先后調用 onDestroy() 和 onCreate())。重啟行為旨在通過利用與新設備配置匹配的備用資源自動重新加載您的應用,來幫助它適應新配置。

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

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

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

  1. 在配置變更期間保留對象

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

  2. 自行處理配置變更

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

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

<activity android:name=".MyActivity"
          android:configChanges="orientation|keyboardHidden"
          android:label="@string/app_name">

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

注意:從 Android 3.2(API 級別 13)開始,當設備在縱向和橫向之間切換時,“屏幕尺寸”也會發生變化。因此,在開發針對 API 級別 13 或更高版本(正如 minSdkVersion 和 targetSdkVersion 屬性中所聲明)的應用時,若要避免由于設備方向改變而導致運行時重啟,則除了 "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 類。

(責任編輯:卓一哥)
織夢二維碼生成器
頂一下
(0)
0%
踩一下
(0)
0%
------分隔線----------------------------
發表評論
請自覺遵守互聯網相關的政策法規,嚴禁發布色情、暴力、反動的言論。
評價:
表情:
用戶名: 驗證碼:點擊我更換圖片
欄目列表
推薦內容