官方解讀Activity之二 – Android移動開發技術文章_手機開發 Android移動開發教學課程

本文接著上一篇寫:

配置改變
如果設備的配置(被定義為Resources.Configuration類)被改變瞭,那麼所有顯示用戶界面的都需要被更新以適應新的配置。因為Acitivity是和用戶交互的首要機制,它包含瞭對配置文件改變的特殊支持。
除非你特殊指定,否則,配置文件的改變將會導致你當前的activity被銷毀,經歷瞭一個正常的activity的生命周期:onPause()、onStop(0和onDestroy()。如果此activity目前處在屏幕的最前端,或者是對用戶可見,一旦那個activity實例的onDestroy()被調用,那麼一個新的activity實例將會被創建,並且新創建的實例將會從 onSaveInstanceState(Bundle)中獲得之前那個activity的狀態。為什麼要這麼做呢?是因為任何應用程序的資源,包括佈局文件,都能夠因為任何配置文件中的配置值而發生改變。因此,對待配置文件的改變最保險的方式就是重新獲得所有的資源,包括佈局文件,圖片資源以及字符資源。由於activity一定知道如何保存他們自己的狀態並且利用這些狀態重新創建自己,這就是一個簡便的方法,讓activity利用新的配置文件重啟自己!
在一些特殊的情況下,你可能想基於一種或者多種配置文件的改變而避開重啟你的activity,這可以通過manifest文件中的 android:configChanges屬性來實現。對你聲明在此的任何類型的配置文件的改變,你都將再你的activity中調用onConfigurationChanged(Configuration)方法,而不是通常的重啟行為。如果出現瞭一些你並未在此聲明的配置文件改變類型,那麼,此activity將會重啟並且onConfigurationChanged(Configuration)將不會被調用!
啟動Activities並獲取結果
startActivity(Intent)方法被用來啟動一個新的activity,新啟動的activity將會位於棧頂,該方法僅有一個參數,一個 Intent,該Intent被用來描述即將被啟動的那個activity。
有的時候你也許希望當一個activity結束的時候可以從期中獲得一個結果。例如:你可能會啟動一個activity使得用戶可以從聯系人列表中選取一個記錄,當選取結束後,該activity可以返回你選中的記錄。為瞭達到這樣的目的,你可以調用startActivityForResult(Intent, int)這個方法來啟動activity,該方法包含第二個參數,用於標識本次調用的一個整數,該方法的返回值會通過 onActivityResult(int, int, Intent)方法返回。
當一個activity已經存在,那麼他就可以調用setResult(int)返回數據給它的持有者,他必須總是提供一個返回碼,可以使標準的結果RESULT_CANCELED, RESULT_OK或者是任何從RESULT_FIRST_USER開始自定義的代碼。另外,它可以返回一個可選的intent,這個intent可以包含任何你想要的數據。所有的這些信息都會返回給它的持有者的Activity.onActivityResult(),伴隨著前面提到的整型參數。
如果一個子activity由於任何原因失敗瞭(例如:崩潰),那麼父activity將會收到RESULT_CANCELED的返回碼。

 

public class MyActivity extends Activity { 
     … 
 
     static final int PICK_CONTACT_REQUEST = 0; 
 
     protected boolean onKeyDown(int keyCode, KeyEvent event) { 
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { 
             // When the user center presses, let them pick a contact. 
             startActivityForResult( 
                 new Intent(Intent.ACTION_PICK, 
                 new Uri("content://contacts")), 
                 PICK_CONTACT_REQUEST); 
            return true; 
         } 
         return false; 
     } 
 
     protected void onActivityResult(int requestCode, int resultCode, 
             Intent data) { 
         if (requestCode == PICK_CONTACT_REQUEST) { 
             if (resultCode == RESULT_OK) { 
                 // A contact was picked.  Here we will just display it 
                 // to the user. 
                 startActivity(new Intent(Intent.ACTION_VIEW, data)); 
             } 
         } 
     } 
 } 
public class MyActivity extends Activity {
     …

     static final int PICK_CONTACT_REQUEST = 0;

     protected boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             // When the user center presses, let them pick a contact.
             startActivityForResult(
                 new Intent(Intent.ACTION_PICK,
                 new Uri("content://contacts")),
                 PICK_CONTACT_REQUEST);
            return true;
         }
         return false;
     }

     protected void onActivityResult(int requestCode, int resultCode,
             Intent data) {
         if (requestCode == PICK_CONTACT_REQUEST) {
             if (resultCode == RESULT_OK) {
                 // A contact was picked.  Here we will just display it
                 // to the user.
                 startActivity(new Intent(Intent.ACTION_VIEW, data));
             }
         }
     }
 }
保存連續的狀態
activity一般需要處理兩種持續的狀態:一種是共享的文檔類型的數據(典型的是利用content_provider存儲再SQLite中);另一種是內部狀態例如:用戶的偏好。
對於content provider數據,建議activities利用本地編輯的模型。那就是,用戶做出的任何編輯都會立即產生作用,而不需要額外的確認的步驟,支持這種模型需要遵守如下兩條規則:
1、當創建一個新的文檔,那麼備份的數據庫條目和文件就會立即被創建。例如:當用戶要寫一個新的郵件時,那麼一條新的記錄就會隨著開始輸入數據而被創建,以至於如果用戶瀏覽其他的activity,這個郵件將會出現在草稿箱中。
2、當activity的onPause()方法被調用,那麼他就會把用戶做出的任何改變提交到後端的content provider或者是文件。這將會確保那些改變對於那些即將運行的activity是可見的,你可能會想在activity的生命周期中更加積極主動的保存數據,例如:在啟動一個新的activity之前,在結束一個activity之前,當用戶改變輸入框時。
這個模型被設計用來在用戶瀏覽多個activity防址數據的丟失,並且允許系統在activity被暫停之後安全的殺死它。這意味著用戶按下BACK鍵並不意味著“取消”,而是意味著保存當前的activity的內容並且離開當前的activity,在一個activity中取消編輯需要通過其他的一些機制,例如一個明確的“恢復”或者“撤銷”選項。
關於content providers的詳細內容可以查閱 content package,這些都是關於在activities之間調用和傳播數據的不同之處重要方面。
Activity同樣提供瞭API來管理與activity有關聯的持續的狀態。這都是可以被拿來使用的,例如:要記住用戶的日歷顯示(日視圖還是周視圖)或者瀏覽器的默認主頁。
Activity持久的狀態是通過getPreference(int)來管理的,允許你去獲取並修改一系列和activity有關的鍵值對。對於多個應用程序組件(activities,receivers,services,provides)共享的偏好設置,你可以通過隱含的Context.getSharedPreferences()方法來通過特殊的名字獲取偏好設置的一些對象。(註意:再多個應用程序包中共享設置的數據是不可能的,對於這種情況,你需要使用content provider).
下面有一個從存有用戶設定的顯示模式的calendar 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(); 
     } 
 } 
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();
     }
 }
權限
啟動特殊activity的權利是在manifest文件中的<activity>標簽中聲明後被強制執行的。通過這種做法,其他的應用程序需要再他們自己的manifest文件中聲明相應的<uses-permission>元素才能啟動上面所說的特殊的activity。

要想查看詳細的關於權限和安全的內容,可以查閱Security and Permissions文檔。

 


進程的生命周期
Android系統試圖盡可能的保持進程,但是不幸的是,當系統內存過低時,系統不得不殺死一些老的進程來釋放內存空間。進程也有四種狀態,這四種狀態都是基於運行再進程中的activity的狀態,系統會優先殺死一些不太重要的進程而不是殺死重要的進程。
1、前臺的activity
2、可見的activity
3、後臺的activity
4、空的進程
有的時候,一個Activity也許需要長時間的運行,即要獨立的存在於它自己的activity生命周期,一個例子就是:也許照相的應用程序允許你上傳照片到網上,而上傳可能會需要比較長的時間,那麼這個應用程序應當允許用戶離開上傳照片的activity,但是上傳照片的進程還是要處於運行狀態。為瞭達到這樣的目的,你的應用程序需要再你上傳照片的地方開啟一個service。這就允許系統給你的應用賦於恰當的優先級,獨立於你原來的activity,不管原來的activity處於paused、stopped或者是finished。

摘自 chenlong12580的專欄

發佈留言