- 一個 Android 應用程式由數個 activity 組成,每個 activity 代表一個畫面,該畫面一般與螢幕等大,也可以小於螢幕。
- 每個應用程式都會有一個名為 main 的 activity,用來啟動該應用程式。
- 每個 activity 可以啟動另一個 activity,當子 activity 啟動後,父 activity 會暫停執行(onPause),直到子 activity 因使用者按下 Back 而關閉後(onPause, onStop, onDestroy)才會重新執行(onResume)。
- Android 以堆疊的方式(last in, first out)實做 activity 間的關係,也就是子 activity 疊在父 activity 上,孫 activity 又疊在子 activity 上。
- 繼承 Activity 或其子類別。
- 實做因 activity 狀態改變而觸發的 callback method,最重要的就是 onCreate 與 onPause。
- onCreate 負責初始化必要的物件與呼叫 setContentView 設定畫面。
- onPause 表示 user 暫時離開或永久離開,要將該存的資料儲存起來。
- Activity class 完成後,得在 AndroidManifest.xml 定義該 activity,<activity> 有很多像是 label 或者 icon 的屬性可以設定,請參考 這裡。
<manifest ... > <application ... > <activity android:name=".ExampleActivity" /> ... </application ... > ... </manifest >
- <activity> 可以使用 <intent-filter> 來設定 activity 的啟動方式,每個 Android 應用程式預設都會有以下的 <intent-filter> 設定值,第一個設定值表示該 activity 為應用程式的入口,第二個設定值表示 user 可以啟動該 activity,每個應用程式最多只有一個 activity 可以有以上的設定值,<intent-filter> 的詳細資訊請看 這裡。
<activity ...> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
- 不想對其他應用程式開放的 activity 就不要定義 <intent-filter>,沒有定義 <intent-filter> 的 activity 只能給自身的應用程式使用。
- 可以使用 startActivity() 啟動 main activity 以外的 activity,傳入 Intent 來指定要啟動的 activity,不限制同一個應用程式裡的 activity,也可以透過 Intent 傳送資料過去。
startActivity(new Intent(this, ExampleActivity.class));
- 若要透過 Intent 啟動其他應用程式的 activity,例如寄送 email 或傳送簡訊,這時因為不知道實際的 activity 名稱,可以用 action 代替,Android 會依據 action 去找出適合的 activity 來執行,甚至當同一的 action 有多個 activity 時,Android 會讓 user 做選擇,呼叫外部程式是 Intent 真正厲害的地方。
Intent intent = new Intent(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_EMAIL, recipientArray); startActivity(intent);
- 有時候要從新 activity 裡取得資料,那可以改用 startActivityForResult() 來啟動 activity,並實做 onActivityResult 來取得回傳的資料。
private void pickContact() { Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI); startActivityForResult(intent, PICK_CONTACT_REQUEST); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) { Cursor cursor = getContentResolver().query(data.getData(), new String[] {Contacts.DISPLAY_NAME}, null, null, null); if (cursor.moveToFirst()) { int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME); String name = cursor.getString(columnIndex); // ... } } }
- 可以呼叫 finish() 結束本身的 activity,也可以呼叫 finishActivity(requestCode) 結束剛啟動的另一個 activity(怎會有這種機會?)。
- 一般來說,這兩個 method 是用不到的,因為 Android 會自動管理所有的 activity 的生命週期。
- Activity 有三種狀態:Resumed、Paused 與 Stopped。
- Resumed: 位於畫面最上層,user 使用中,也可以稱為 Running。
- Paused:被另一個 activity 蓋過去,也許還可以看到畫面,只要上面的 activity 沒有佔滿整個畫面或者使用透明背景的話,這時 activity 還是活著的,只是沒有在動,當系統記憶體不足時有可能會被殺掉。
- Stopped:完全看不到,但還是活的,隨時可能被系統殺掉。
- 當 activity 處於 Paused 或 Stopped 狀態時,系統可能透過 finish() 或者直接殺掉 process 來結束他的生命,所以當進入 Paused 或 Stopped 狀態時,要先將後事交待好。
- 所有 callback method 的執行時機:
- onCreate:建立 activity 時。
- onStart:activity 置於畫面最上層時。
- onResume:activity 回到畫面最上層時。
- onPause:被另一個 activity 蓋住時。
- onStop:完全看不到 activity 時。
- onDestroy:activity 即將被殺掉時。
- 實做上述所有 callback method 時,一定要先呼叫相對應的 super.onXXX()。
- 三種生命週期:
- 出生到死亡:即從 onCreate() 到 onDestroy(),分別只會被執行一次,onCreate() 要初始化所有要用的物件,包括 layout view,onDestroy() 要釋放所有資源。
- 可見的狀態:從 onStart() 到 onStop(),分別負責啟動與停止畫面上的動作,不一定是 focus 狀態,可能被其他 activity 蓋住,可以被執行多次。
- 前景的狀態:從 onResume() 到 onPause(),user 使用中,因為這兩個 method 會被頻繁的執行,所以不要在裡面寫太麻煩的 code。
- 上圖最重要的一點:onResume() 不只在 onPause() 之後執行,在第一次啟動 activity 時,也會在 onStart() 之後執行 onResume()。
- 系統可能在 onPause()、onStop() 或 onDestroy() 執行後,因為記憶體需要,隨時殺掉該 activity,而 onPause() 是三個 method 裡面第一個會被執行的 method,在系統可能在尚未執行 onStop() 或 onDestroy() 前殺掉 activity,所以 onPause() 裡要將必要的資料寫回資料庫,以及停止動畫與停止消耗 CPU 的動作,但要小心 onPause() 不可以執行太久。
- onSaveInstanceState()
- 當 activity 被系統殺掉後,如果 user 再回到該 activity,系統會重新建立該 activity,但是 user 並不知道 activity 發生什麼事了,所以 user 會期望回復到離開前的樣子,這時就要實做 onSaveInstanceState() 來保留 user 走過的痕跡到 Bundle 物件裡,然後系統在重新建立 activity 時,會將該 Bundle 物件傳給 onCreate(),就這樣,像是什麼事都沒發生過一樣。
- onSaveInstanceState() 多半在 onStop() 前呼叫,但也可能在 onPause() 前呼叫,但不一定總是會呼叫,因為當 user 按下 BACK 時,表示 user 知道要離開 activity 了,那就沒有必要呼叫 onSaveInstanceState()。
- 並不一定要實做 onSaveInstanceState(),因為像是 EditText 或 CheckBox 之類的 View 元件有預設的 onSaveInstanceState() 實做,元件只要加上 android:id 屬性就會保留狀態了,換句話說,如果沒有加 android:id 屬性,則表示不想要保留狀態,也可以用 android:saveEnabled 或者 setSaveEnabled() 來強制 View 元件不要保留狀態。
- 那 onSaveInstanceState() 裡到底要做什麼?activity 裡的 member values,但是不要跟 onPause() 裡紀錄到資料庫的資料搞混,前者只是紀錄 user 走過的痕跡,後者紀錄的是永久的資料。
- 記得要呼叫 super.onSaveInstanceState(),不然 View 元件就會呆掉了。
- 要怎麼測試 onSaveInstanceState() 呢?轉 90 度就可以了,因為要套用新的 layout,所以系統會將 activity 殺掉再重新建立。
- 系統執行時動態改變設定值,如轉 90度、開啟鍵盤或者改變語系,都會促使系統殺掉再重新建立 activity,所以一定要實做 onSaveInstanceState() 與 onRestoreInstanceState(或者 onCreate())。
- 當前後兩個 activity 有共用資料或資源時,要注意兩個 activity 的執行順序,最重要的是共用資源得在 onPause() 裡關閉,不可以在 onStop() 裡。
- aActivity.onPause()
- bActivity.onCreate()
- bActivity.onStart()
- bActivity.onResume()
- aActivity.onStop() - 如果看不到 aActivity 的話,才會執行
沒有留言:
張貼留言