Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android的Activity進程被殺的解決辦法

Android的Activity進程被殺的解決辦法

編輯:Android開發實例

我們要了解Android手機開發與桌面開發有一個主要不同之處:通常在一部Android手機裡同時運行著多個應用(app),每個app對應一個系統進程,當系統需要更多的資源(如內存)而空閒資源不足時,Android系統就會選擇殺掉一些“低優先級”的進程以便釋放所需資源。

Android系統是如何確定進程優先級的高低的呢?

  • 如果一個app正在與用戶交互,那麼它所在的進程具有最高優先級;
  • 其次,如果一個app是可見的,例如被一個對話框部分遮擋,它所在進程具有第二高的優先級;
  • 再次,如果app當前是不可見的,也就是被切換到了後台,則它所在進程具有第三高的優先級;這裡要補充一點,如果這個後台app啟動了一個service,則它比一般的後台app優先級高一些。
  • 最後,如果一個進程裡沒有包含任何app,這個進程的優先級是最低的。

當系統資源嚴重不足時,任何一個進程都有可能被殺掉,而當用戶想回到一個已經不存在於內存中的Activity時,系統只得新建一個這樣的Activity對象並調用它的onCreate()方法進行恢復。所以有時出現這種狀況:一個app大部分時間運行很好,偶爾在切換Activity時出現空指針異常導致強制關閉,這多半是在onCreate()方法裡使用了已經被重置為空的對象(例如intent裡的變量)造成的。即使不出現異常,也會造成表單數據丟失等嚴重影響使用體驗的問題。

要解決這類問題,切不可抱“現在手機內存大,進程一般不會被殺掉”這種僥幸心理,而應該以“應用隨時都會被殺掉”的態度來謹慎處理,下面介紹Google建議的方式。

解決方法

由於Activity隨時可能需要重建,所以我們要做的事情就是在適當的位置將Activity所需數據進行持久化(從ram復制到rom或sd卡),並在onCreate()方法裡利用這些數據恢復現場。

Activity有兩類數據需要進行持久化處理:“文檔類型數據”和“內部狀態類型數據”,前者例如用戶正在編輯的表單,後者如用戶偏好。

一、為了持久化文檔類型的數據,Google建議使用”即時生效”(edit in place)的編輯策略,具體的方式如下:

  • 用戶新建文檔時,在SQLite數據庫(根據需要也可以使用preference)裡也立即新建一條記錄。(與此相對的方式是:為用戶提供一個“保存”按鈕,只有當用戶按下按鈕時才將文檔保存到數據庫。)
  • 當用戶離開當前Activity時,onPause()方法會被觸發,在這個方法裡將當前正在編輯的文檔持久化到數據庫。這樣一來,如果用戶是從這個Activity切換到另一個相關Activity,仍然可以看到剛剛保存的內容。

這種方式可以最大限度避免數據丟失,只要onPause()方法被觸發執行,即使Activity所在進程被系統kill掉也不會造成數據丟失。唯一要注意的是,界面上最好能提供一個“取消”按鈕或菜單,以便讓用戶可以選擇不保存對文檔的更改。

二、為了持久化內部狀態類型的數據,可以在onPause()裡使用Activity#getPreferences(int)方法,這個方法返回SharedPreferences類型的對象,利用它可以記錄用戶對這個Activity的偏好信息。例如一個日歷應用,用戶可以選擇顯示為周視圖或月視圖,這樣的信息作為內部狀態記錄到SharedPreferences對象以後,下次再打開這個Activity時就可以按用戶上次的選擇來顯示日歷了。

以下代碼來自官方文檔,演示了如何持久化並恢復一個Activity的當前顯示模式:

 
 public class CalendarActivity extends Activity {
     ...

     static final int DAY_VIEW_MODE = 0;
     static final int WEEK_VIEW_MODE = 1;

     private SharedPreferences mPrefs;
     private int mCurViewMode;

     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         //取回之前持久化的日歷顯示模式
         SharedPreferences mPrefs = getSharedPreferences();
         mCurViewMode = mPrefs.getInt("view_mode", DAY_VIEW_MODE);
     }

     protected void onPause() {
         super.onPause();

         //持久化日歷顯示模式 
         SharedPreferences.Editor ed = mPrefs.edit();
         ed.putInt("view_mode", mCurViewMode);
         ed.commit();
     }
 }
 

是有點麻煩,但為了能讓app穩定運行也值了。

有些同學要問了,為什麼是在onPause()裡持久化而不是在onSaveInstanceState()裡?官方文檔有下面一段話簡要解釋了原因,即前者比後者更可靠,因為onSaveInstanceState()不屬於Activity生命周期的一部分。——既然如此,我想不出onSaveInstanceState()還有什麼其他用途了,大家干脆忘了它吧,還有onRestoreInstanceState()。

Note that it is important to save persistent data in onPause() instead of onSaveInstanceState(Bundle) because the latter is not part of the lifecycle callbacks, so will not be called in every situation as described in its documentation.

注1:關於上面這段話,網上存有一些爭議,我個人還是比較傾向在onPause()裡做持久化——既可靠又好記,唯一的缺點是調用次數稍多。

注2:從Android 3.0(HoneyComb)版本開始,Activity進程在被系統殺掉之前,將保證onStop()方法先執行完成,因此如果我們開發的應用只運行在3.0以上,可以把持久化工作放在onStop()裡以減少持久化的次數。

最佳實踐

不要抱僥幸心理,你的Activity隨時可能被銷毀。

解決方法:在onPause()裡持久化Activity數據,在onCreate()裡恢復現場

參考資料:

ActivitySaving Activity state in Android

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