Androidz之Activity概要学习
Androidz之Activity概要學習
?
1.?????Activity類概述
Activity(活動)是一個單獨的、能獲取焦點的,且能與用戶交互的東西。所以我們通常在Activity類中的onCreate方法中調用setContentView(View)來在UI布局中創建窗口(window)。Activities經常占滿全屏,當然,它們也可以作為浮動的窗口(通過windowIsFloating方法實現),或是嵌入到另一個Activity(使用ActivityGroup)中。
?
所有的Activity子類中有兩個方法是要實現的:
(1)?? onCreate(Bundle)
我們在雙擊應用圖標時,系統根據AndroidManifest.xml的android:name來創建Activity,然后調用此回調函數,最重要的是我們可用定義UI布局資源文件作為參數調用setContentView(int)來設置用戶界面,和使用findViewById(int)來獲得UI中的widgets(小組件,比如按鍵),這需要通過編譯的方式來實現(相對于xml定義的方式)。
?
下面是AndroidManifest.xml文件的相關部分:
<activityandroid:name="com.example.helloworld.MainActivity"android:label="@string/app_name" ><intent-filter><actionandroid:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER"/></intent-filter> </activity>(2)?? onPause()
用戶離開(盡管這不總是意味著該Activity將被銷毀)activity時候系統調用此回調函數來處理,最重要的是用戶的任何改變在這點上應該提交(通常是ContentProvider保持這些數據),也就是需要完成保存數據的工作以便用戶后面回到你的Activity以恢復之前的狀態。
?
為了使用Context.startActivity()來啟動Activity,必須在Android應用的清單文件(AndroidManifest.xml)中申明Activity才可以在應用中使用該Activity。你可以通過打開Android應用的清單文件,然后添加一個<activity>元素作為<application>的子節點。見上面給出的內容。
?
2.?????開發人員指南
Activity類是應用程序整個生命周期的一個重要組成部分,Activities的啟動方式和組合(put together)是Android平臺應用模式的一個基礎部分。關于Android應用更詳細的觀點(perspective)和activities的行動方式,請參考Application Fundamentals(http://developer.android.com/reference/android/app/Activity.html)和Tasks and Back Stack
(http://developer.android.com/guide/components/tasks-and-back-stack.html)。
?
?
3.?????Fragments
Fragement(段)用Android3.0開始引入,如果之前版本的系統需要支持,就要導入android-support-v4.jar庫。Activity實現可以使用Fragment類來更好模塊化代碼,為大顯示屏構建更復雜的用戶接口和幫助應用程序更靈活是英語小和大屏幕的設備。下面給出一個圖來理解Fragment,更詳細的后面再學習:
圖1
?
?
?
。
4.?????Activity生命周期
系統中的Activities被一個activity棧(activity stack),當啟動一個新的activity,它被放到棧頂和成為正在運行的activity。前一個activity保留在棧頂的下一個位置,除非新的activity退出,否則前一個activity不會回到前臺。
?
一個activity本質上有4個狀態:
(1)??Active/running
表示activity處于屏幕前臺,也就是在棧頂。
?
(2)??Pause
表示activity失去焦點,但依然可見,也就是說,有其它可見的activity位于本activity(這是相對于activity在stack的位置來說的)。處于paused狀態的activity依然是活動的(它保持所有狀態和信息(member)的信息,且仍然由windows manager管理)但在系統空閑內存極低時有可能被Android系統殺掉(kill)。
?
(3)??Stopped
activity完全被另一個activity覆蓋,雖然它依然保持所有狀態和成員信息,但它不在可見,所以它的窗口是隱藏的。并在如果系統在需要內存時將殺掉此activity
?
(4)??如果一個activity處于paused或者stopped,系統能夠命令其finish或者簡單
kill其進程。當它重新在用戶面前顯示的時候,它必須完全重新啟動并且將其關閉之前的狀態全部恢復回來。
?
下面的圖展示了activity重要的狀態路徑,方矩形表示回調函數,我們可以實現這些方法從而使activity在狀態改變時執行我們制定的操作,帶顏色的橢圓形是activity的主要狀態:
圖2
?
在監控我們activity時,有三個重要的循環(loop):
(1)??整個生命周期(entire lifetime)
從開始調用onCreate(Bundle)到最終調用onDestroy(),activity在onCreate()中創建所有的全局狀態,在onDestroy()中釋放所有的資源。比如,如果它有一個從網絡下載數據的后臺(background)線程,那activity就會在onCreate()中創建線程,而在onDestroy()中停止這個線程。
?
(2)??可見的生命周期(visible lifetime)
從調用onStart()到調用相應的onStop(),在這段時間用戶能夠在屏幕中看這個activity,盡管它不一定在前臺也不一定和用戶交互。在這兩個辦法之間我們可以維護(maintain)需要顯示給用戶的資源。比如,我們可以在onStart()中注冊一個BroadcastReceiver來監控那些影響我們UI的變化,在用戶不在需要我們的顯示時,可在onStop()中注銷這個BroadcastReceiver。onStart()和onStop()辦法可以多次被調用,因為activity對于用戶來說可以是可見或是隱藏的。
?
(3)??前臺生命周期(foreground lifetime)
從調用onResume()到調用相應的onPause(),在這段時間activity在所有其他activity的前面,且和用戶交互。一個activity可以經常在resumed和paused狀態之間切換,比如當設備進入sleep狀態,activity的結果返回時,且新的intent到來時,所以這個兩個方法的代碼應該非常簡短。
?
下面的方法定義了activity的整個生命周期,如下面所示:
public classActivity extends ApplicationContext {protected void onCreate(BundlesavedInstanceState);protected void onStart();protected void onRestart();protected void onResume();protected void onPause();protected void onStop();protected void onDestroy();}所有的這些都是hook,我們可以重載這些方法從而使activity改變狀態時執行適當的操作。所有的activity都要實現onCreate(Bundle)來進行初始化配置,大多數也實現onPause()來提交數據的改變和準備停止和用戶的交互。在實現這些方法時,我們還應該要調用activity的父類,比如:
@Overrideprotected void onCreate(BundlesavedInstanceState) {super.onCreate(savedInstanceState); … }大體上activity生命周期的變化看起來像下圖描述的:
圖3
(1)??onCreate()
當activity第一次被創建調用onCreate(Bundle),這里我們應該進行所有的一般靜態設置:創建view,綁定數據到list中,等等。如果activity之前是凍結狀態,此方法的Bundle參數包含了狀態信息。
如果是首次創建,本方法之后將會調用onStart(),如果activity是停止后重新啟動,將調用onRestart()。
?
(2)??onRestart()
在activity停止之后重新啟動時調用此方法,總是緊跟著onStart()方法。
?
(3)??onStart()
當activity對用戶即將可見時調用,如果activity作為前臺接著蔣調用onResume(),如果要隱藏activity,接著將調用onStop()。
?
(4)??onResume()
當activity即將和用戶交互時調用,此時activity處于activity棧頂,已經獲取用戶的輸入,如果其他的activity需要恢復顯示,接著將調用onPause()。
?
(5)??onPause()
當系統準備恢復前一個activity時調用,此方法一般用于提交被改變且沒保存的永久性數據,停止動畫和其他消耗CPU資源的事情,等等。此方法的實現必須是非常快速,因為下一個activity不能恢復直到此方法返回。如果activity返回到前端,接著調用onResume();如果對于用戶隱藏,接著調用onStop()。
?
(6)??onStop()
當activity不再對用戶可見時調用,因為其他activity已經被恢復和覆蓋整個activity。在一個新activity啟動和一個已經存在的activity被切換到前臺,或是整個activity即將退出(destroyed)時都會發生這樣的場景。
如果activity重新回到前臺和用戶交互時接著調用onRestart();如果activity要退出則調用onDestory()。
?
(7)??onDestroy()
在activity被銷毀前調用的最后一個方法,當activity完成時出現這種情況(對activity調用finish()方法,或是系統為了節省空間臨時銷毀此activity的實例。)。我們可以通過調用isFinishing()方法來區分這兩種情況。
?
主要上表上”killable”這一列—對于那些標記了killable的方法,在這些方法返回后,activity的進展可能隨時被系統kill而不再執行activity中任何代碼。所以,我們應該在onPause()方法中保存何永久數據(比如用戶編輯)。除此之外,onSaveInstanceState(Bundle)方法在activity切換為后臺狀態時被調用,允許我們保存activity的任何動態實例狀態到Bundle中,如何需要重新創建此activity,此參數后來被onCreate(Bundle)函數接收。
@Overrideprotected void onCreate(BundlesavedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);if (savedInstanceState == null) {getSupportFragmentManager().beginTransaction().add(R.id.container, newPlaceholderFragment()).commit();} }請注意,在onPause()中保存永久數據非常重要,而不是onSaveInstanceState(Bundle),因為后者不是生命周期回調(liftcycle callbacks)的一部分。
?
大家了解一下,相對于HONEYCOMB(Android3.0)之前的Android版本,后面的系統這些語意(semantics)稍微有些改變。從HONEYCOMB版本開始,只有onStop()返回后才能kill一個應用。
?
5.?????配置改變(Configuration Changes)
如果設備的配置(在Resources.Configuration類中定義)發生改變,那么所有用戶界面上的顯示需要更新來匹配新的配置。因為Activity是和用戶交互的最主要機制,它包含了處理配置改變的特別支持。
?
除非你專門指定,一個配置的改變(比如屏幕分享,語言,輸入設備等等的改變)將引發我們當前activity被銷毀,這個銷毀的動作是通過一個正常activity生命周期過程(相應的調用onPause(), onStop(), and onDestroy()來處理)。如果activity已經在前臺(foreground)或是對用戶可見,當這個實例(instance)的onDestroy()被調用完成后就重新創建這個activity的實例,并將onSaveInstanceState(Bundle)保存的前一個實例傳遞給新的實例。
?
由于任何應用資源(包括layout文件)都有可能因為配置值而改變,所以處理配置改變的唯一安全的方式就是重新獲取所有的資源,包括layouts(布局)、drawables(繪圖資源)和strings(字符串資源)。由于activities已經知道如何保存它們的狀態并能夠從哪些狀態中重新創建自身,所以用新配置來重啟activity自身是一種便利的方式。
?
在一些特殊的情況中,我們希望當一種或是多種配置改變時避免重啟activity,可以通過在mainfest文件中設置android:configChanges屬性來實現這一點。在這里可以聲明activity可以處理的任何改變,當這些配置改變時不會重啟activity,而是會調用activity的onConfigurationChanged(Configuration)方法。如果改變的配置中有activity無法配置的配置(在android:configChanges并未聲明),我們的activity仍然要被重啟,而onConfigurationChanged(Configuration)將不會被調用。
?
6.?????啟動activity并獲取結果(Starting Activities and Getting Results)
startActivity(Intent)用來啟動一個新的activity,這activity將位于activitiy棧的棧頂。這個方法只有一個參數Intent,此參數描述將被執行的activity。
?
有時候,我們希望在一個activity結束時得到它返回的結果。比如,我們開啟一個activity來讓用戶從通訊錄中選擇一個人,當它結束時將會返回被選擇的人。為了得到這個返回的信息,我們調用startActivityForResult(Intent, int)方法來啟動新的activity,此方法第2個整形參數作為這次調用的標識。然后通過我們的onActivityResult(int, int, Intent)方法返回結果,此方法第1個參數就是之前調用所用到的標識。
?
當一個activity退出,它調用setResult(int)返回數據給它的父進程(parent),此方法必須提供一個結果碼,這個結果碼可是是標準結果碼RESULT_CANCELED,RESULT_OK,也可以是其他任何從RESULT_FIRST_USER開始的值。此外,它還可根據需要返回一個包含了任何額外數據的Intent。所有這些信息都會在父activity的回調函數Activity.onActivityResult()中出現,并連同最初提供的識別標記一起(此處有些拗口,意思其實就是子activity返回的內容、返回碼、識別標記都將作為參數,按照不同的返回情況來調用父activity的Activity.onActivityResult()方法,以實現出現各種返回時父activity做出響應的處理)。
?
如果子activity由于某種情況(比如crashing)失敗,父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 thempick 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 wewill just display it// to the user.startActivity(new Intent(Intent.ACTION_VIEW, data));}}}}
?這里是一個例子,說明了如何啟動一個新的activity并處理結果。
?
7.?????保存持久數據(Saving Persistent State)
通常有兩種持久狀態需要activity處理:類似于共享文檔(代表性的是使用一個content provider存儲在SQLite數據庫中)和像用戶參數一樣的內部狀態。
?
對于content provider數據,我們建議activity使用“編輯即生效”(edit in place)的用戶模型。就是說,用戶的任何編輯都立即生效而不要求進一步的確認。下面兩天規則通常使支持這種模型成為一件簡單的事情:
(1)??當創建一個新文檔,立即為它創建后臺數據庫條目(backing database entry)或是文件。比如,如果用戶寫一封新郵件,當他們開始輸入數據時馬上創建一個新的數據庫條目,所以即使他們輸入后進入其他任何activity,這封郵件也會出現在草稿箱中。
(2)??當activity的onPause()被調用時,它應該講用戶的所做的任何修改提交給后臺content provider或是文件,這樣可確在準備運行的acitvity中看到這些修改。我們可能在activity生命周期的關鍵時刻更積極(more aggressively)提交數據,比如在啟動一個新的activity之前,在完成自己的activity之前,在用戶輸入域切換時,等等。
?
這模型是為了避免用戶在activity之間切換時數據丟失而設計的,并允許系統在activity被paused之后的任何時刻安全銷毀activity(因為在其他地方可能需要系統資源)。主要這里暗示用戶點擊activity的BACK鍵并不意味著cancel,它意味著安全保存當前內容后離開這個activity。Activity中的取消編譯通過其他幾只來提供,比如一個顯示的“revert(還原)”和“undo(撤銷)”選項。
?
如果要了解content providers更多的內容請看content package部分,這是不同的activity如何調用和彼此之間傳遞參數的關鍵部分。
?
Activity類也提供API來管理與activity相關聯的內部持久狀態,比如,這可以用來記憶日歷的首選初始顯示(日期視圖或周視圖)或web瀏覽器中用戶的默認主頁(default home page)。
?
Activity持久狀態使用getPreferences(int)方法來管理,允許我們檢索和修改一系列與activity相關聯的名稱/值對。如果要在多個應用組件(activites、receivers、services、providers)之間共享數據,我們可以使用底層方法Context.getSharedPreferences()來檢索一個特定名稱下的參數對象(請注意application packages之間不能共享設置數據----這時你就需要一個contentprovoders來實現。)
?
這里是從一個日歷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();}}8.?????許可(permission)
我們可以通過在activity所屬應用的mainfest文件中對應的<activity>標簽聲明來顯示哪些應用可以啟動此activity。如果進行了聲明,其他應用需要在他們自己的manifest文件中聲明對應的<uses-permission>元素才可以啟動這個activity。
?
當啟動一個activity,我們能夠在Intent設置
Intent.FLAG_GRANT_READ_URI_PERMISSION
和/或Intent.FLAG_GRANT_WRITE_URI_PERMISSION。這樣即可授權acitvity來訪問Intent中特殊的URIs。此訪問被保持直到activity完成(在正在銷毀的宿主進程和其他臨時破壞之間切換時也會被保持)。自從GINGERBRED(Android2.3.3)開始,如果這個activity已經被創建和一個新的Intent正被傳送給onNewIntent(Intent),任何新的被授權的URI權限將被添加到已存在的這個activity中。
?
如果想了解更多關于許可和安全方面的信息,請參考Security and Permissions部分。
?
9.?????進程生命周期(process lifecycle)
Android系統盡量久的保留應用程序,但是當內存降低時最終會移除舊的進程。就想activity生命周期描述的一樣,移除哪個進程取決于與用戶交互的親密程度。一般來說,進程基于運行的activity來分為4個狀態,下面根據狀態的重要程度來排列。系統會在kill更重要的進程(第1個)之前會先kill哪些不是很重要的進程(最后一個)
?
(1)??前臺(foreground)activity(此activity位于屏幕最上方,正與用戶交互)被認為是最重要的,它的進程只能在萬不得已的情況下才能kill。如果使用了多于設備的有效內存,一般來說這時候設備處于內存分頁(paging)狀態,為了使用戶界面保持響應才會發出kill請求。
(2)??可見的activity(對用戶可見當不在前臺,比如處在浮動對話框后)被認為是非常重要的,除非為了保證前臺activity運行,否則不會被kill。
(3)??后臺activity(對用戶不可見,并處于paused狀態的activity)就不是很重要了,系統為了保證前臺和可見進程的運行會回收內存而安全地kill它們。如果它的進程需要被kill,當用戶切回(navigate back to)到此activity(使它在屏幕上再次可見),它的onCreate(Bundle)辦法將被以保存了之前狀態的savedInstanceState來調用,此參數由onSaveInstanceState(Bundle)辦法提供。所以它能夠在用戶上次離開它的地方重啟自身。
(4)??空進程是一個沒有運行activity或是其他組件(比如Service或是BroadcastReceiver類)的進程,它們會在系統內存比較低時被快速kill。因此,當你要在activity外運行任何的后臺操作時,必須在BroadcastReceiver or Service的上下文運行,這樣才能確保系統需要將我們的進程保留。
?
有時候一個activity可能需要運行一個長時間操作,且它不依賴于activity生命周期而存在。例如一個照相應用運行我們上傳照片到web站點,上傳可能需要很長時間,在上傳過程中允許應用離開應用但還保持工作。為了實現這點,我們的activity應該啟動一個Service來執行此工作。這使系統能在我們進程上傳數據的過程中夠恰當的區分它的優先級(認為此進程比其他不可見應用更重要),而不管創建此Service的activity的狀態是puased、stopped還是finished。
?
?
?
參考鏈接:
Android開發者Activity
http://developer.android.com/reference/android/app/Activity.html
Android Activity 詳解
http://www.2cto.com/kf/201303/197684.html
?
android之activity生命周期(轉載)
http://www.cnblogs.com/draem0507/archive/2012/11/28/2793332.html
?
兩分鐘徹底讓你明白Android Activity生命周期(圖文)
http://kb.cnblogs.com/page/70125/
?
總結
以上是生活随笔為你收集整理的Androidz之Activity概要学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android开发者必备的42个链接
- 下一篇: AndroidApplication F