安卓基礎<第二章>
四大組件之一:activity
顯式意圖和隱式意圖
l 顯式跳轉:在可以引用到另外一個Activity的字節碼,或者包名和類名的時候,通過字節碼,或者包名+類名的方法實現的跳轉叫做顯示跳轉。顯示跳轉多用於自己工程內部多個Activity 之間的跳轉,因爲在自己工程內部可以很方便地獲取到另外一個Activity 的字節碼。
l 隱式跳轉:隱式跳轉不需要引用到另外一個Activity 的字節碼,或者包名+類名,只需要知道另外一個Activity 在AndroidManifest.xml 中配置的intent-filter 中的action 和category 即可。言外之意,如果你想讓你的Activity 可以被隱式意圖的形式啓動起來,那麼就必須爲該Activity 配置intent-filter。
Activity 之間的跳轉都是通過Intent進行的。Intent 即意圖,不僅用於描述一個Activity的信息,同時也是一個數據的載體。
顯式意圖必須指定要激活的包名和路徑名
>激活自己應用程序內部的組件 推薦使用顯式意圖 效率高 通過Intent 的帶參構造函數
Intent intent = new Intent(this, SecondActivity.class);
1. 通過Intent 的setClass 方法
intent.setClass(this,SecondActivity.class);
Intent 可以攜帶的數據類型
1. 八種基本數據類型boolean、byte、char、short、int、float、double、long 和String 以及這9 種數據類型的數組形式
2. 實現了Serializable接口的對象
3. 實現了Android 的Parcelable 接口的對象以及其數組對象
隱式意圖 只需要指定action和data就可以了
>清單文件裏面寫過濾器--寫action和data
> 激活別的應用程序界面 ,或者是自己應用程序某個界面需要暴露給別的應用程序調用 效率低
需要去遍歷所有組件匹配開啓
> 一般用在調用系統內部的應用程序 比如照相機 打電話
1. 要跳轉的activity在清單文件裏增在intent-filter
<intent-filter>
<action android:name="自己定義,習慣用包名後加功能名"/>
<categoryandroid:name="android.intent.category.DEFAULT"/> //默認
</intent-filter>
2. 誰要跳轉到這個activity,誰的方法裏面調用
Intentintent = new Intent();
intent.setAction("要跳轉的activity在清單文件裏配置的action");
intent.addCategory("android.intent.category.DEFAULT");-->默認
startActivity(intent);
Ø 隱示意圖需要注意的地方
在清單文件的 intent-filter 裏面還可以配置 data標籤,data標籤可以配置多個不同種類型的
例如:
<dataandroid:scheme="自己定義"/> -->設置前綴,與電話播放器調用很像
<dataandroid:mimeType="text/plain"/> -->定義類型,這裏不能隨意定義
在java代碼裏,如果同時配置了scheme和mineType:
intent.setDataAndType(scheme,mimeType);
如果只配置scheme:
intent.setData();//報錯
如果只配置了mimeType:
intent.setType();//報錯
一、關閉當前Activity
在Activity 中調用finish()方法即可關閉當前Activity。
二、啓動一個Activity 時獲取該Activity 銷燬時的返回值
如果想讓我們的A界面 打開B界面,同時能夠獲取到B界面銷燬時返回的數據,那麼就不能通過startActivity(Intent) 方法去啓動B界面了。必須使用startActivityForResult(Intent intent, int requestCode)方法,該方法必須跟onActivityResult(intrequestCode,int resultCode, Intent data)方法結合着使用才行,當A界面啓動的B界面銷燬前,如果B界面調用了setResult(intresultCode, Intent data)方法,那麼系統就會調用A界面的onActivityResult()方法,同時將數據Intent 的形式傳遞過來。
上面用到了3 個重要API:
1、startActivityForResult(Intent intent, int requestCode)
啓動Activity,同時等待該Activity 返回數據。只有該Activity 銷燬時數據纔會被返回。
參數1:意圖,封裝要啓動的Activity,當然也可以攜帶數據
參數2:請求碼,如果是大於0 的整數,那麼該請求碼會在onActivityResult 中的requestCode中出現,如果小於等於0,則不會被返回。
2、onActivityResult(int requestCode, int resultCode, Intent data)
當打開的Activity 銷燬的時候該方法會被調用,從該方法中獲取銷燬的Activity 設置的數據。
參數1:startActivityForResult 方法中的requestCode
參數2:setResult 方法中的resultCode
參數3:Intent 數據
3、setResult(int resultCode, Intent data)
被打開的Activity 如果想返回數據,則在銷燬前一定要調用該方法,通過該方法設置數據。
參數1:結果碼,該結果碼可以用於區分是哪個Activity 給我們返回的數據
參數2:設置的數據
Activity 的生命週期
學到這裏我們有必要對Activity 有一個全新的認識。Activity已經不能再簡單的認爲就是一個普通的類,其生命週期就是類的加載,對象的的創建和對象的卸載那麼簡單。Activity 從創建到銷燬,整個生命週期是一個非常複雜的過程,該過程由Android 系統負責維護。
Activity 的3 種狀態
我們人類有嬰幼兒時期、青少年時期、中老年時期,Activity 一樣也有3 種狀態:Resumed、Paused、Stopped,這三種狀態是Android 官方給出的,我們翻譯過來可以理解爲:激活或運行狀態、暫停狀態、停止狀態。這3 種狀態的特點如下:
1. Resumed 狀態:Activity 位於前端位置,並且獲取到了用戶的焦點。也就是當前Activity 完全可見也可用。
注意:在Android 中目前只允許同時只能有一個Activity位於前端位置。
2. Paused 狀態:如果另外一個Activity 位於前端位置並且獲取了焦點,但是該Activity 還依然可見,那麼該Activity 就處於了Paused 狀態。比如如果另外一個Activity 雖然位於前端,但是是透明的或者沒有佔滿整個屏幕,那麼就會出現上面的這種情況。位於Paused 狀態的Activity 依然是“存活”着的,但是如果系統內存極端的不足,那麼就有可能被系統“殺死”以便釋放內存。
3. Stopped 狀態:當另外一個Activity 完全將該Activity 遮蓋住的情況下,那麼該Activity 就處於停止狀態了。位於停止狀態的Activity 依然“活着”,但是它已經對用戶完全不可見了,因此只要系統需要釋放內存就會將該Activity“殺死”。
我們編寫的代碼要根據Activity 的不同狀態讓其做不同的工作,比如如果我們的Activity 是用於播放視頻的,那麼當其位於Resumed 狀態時我們可以讓視頻正常的播放,當Activity 位於Paused 狀態的時候,我們也應該讓我們的視頻暫停播放,當Activity 位於Stopped 狀態時我們應該停止播放視頻並釋放資源。
那麼如何讓我們的程序員能夠感知到Activity的狀態變化呢?Android 系統爲了將Activity 狀態的變化通知給我們在Activity 中提供了7 個回調方法。我們只需要在不同的回調方法中完成不同的工作即可。
Activity 生命週期的7 個回調方法
方法名 |
特點 |
OnCreate |
第一次被創建時,一個Activity只能被創建一次
|
onStart |
當用戶可見並可操作2 |
onResume |
獲取焦點 |
onPause |
失去焦點 |
onStop |
該Activity不可見 |
onDestory |
Activity被銷燬 |
onRestart |
將Activity最小化後,重新激活這個Activity |
下圖是Android官方給出的Activity 生命週期圖:
橫豎屏切換時Activity 的生命週期
Android 手機在橫豎屏切換時,默認情況下會把Activity 先銷燬再創建,模擬器橫豎屏切換的快捷鍵是Ctrl+F11。
在類似手機遊戲、手機影音這一類的應用中,這個體驗是非常差的。不讓Activity 在橫豎屏切換時銷燬,只需要在清單文件聲明Activity 時配置<activity>節點的幾個屬性即可,其方式如下:
一. 4.0 以下版本:
android:configChanges="orientation|keyboardHidden"
二. 4.0 以上版本:
android:configChanges="orientation|screenSize"
三. 4.0 以上版本:
android:configChanges="orientation|keyboardHidden|screenSize"
將該參數配置到Activity 中後再切換屏幕方向,那麼Activity就不會再銷燬和重新創建了。但是配置了該參數僅僅是不讓Activity 銷燬和重建,Activity 界面依然會跟着屏幕方向重新調整,那麼如何固定Activity 的方向呢?
固定Activity 的方向
想固定Activity 的方向其實比較簡單,有兩種方法:
1、通過配置文件
在AndroidManifest.xml 中的activity 節點中添加如下屬性。
android:screenOrientation="portrait"
該屬性通常有兩個常量值,portrait:垂直方向,landscape:水平方向。
2、通過代碼
在Activity 的onCreate 方法中執行如下方法。
//垂直方向
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
//水平方向
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
Activity 的啓動模式
Activity 的任務棧
Task Stack(任務棧)是一個具有棧結構的容器,可以放置多個Activity 實例。啓動一個應用,系統就會爲之創建一個task,來放置根Activity;默認情況下,一個Activity 啓動另一個Activity 時,兩個Activity是放置在同一個task 中的,後者被壓入前者所在的task 棧,當用戶按下back 鍵,後者從task 中被彈出,
前者又顯示在屏幕前,特別是啓動其他應用中的Activity 時,兩個Activity 對用戶來說就好像是屬於同一個應用;系統task 和應用task 之間是互相獨立的,當我們運行一個應用時,按下Home 鍵回到主屏,啓動另一個應用,這個過程中,之前的task 被轉移到後臺,新的task 被轉移到前臺,其根Activity 也會顯示到
幕前,過了一會之後,再次按下Home 鍵回到主屏,再選擇之前的應用,之前的task 會被轉移到前臺,系統仍然保留着task 內的所有Activity 實例,而那個新的task 會被轉移到後臺,如果這時用戶再做後退等動作,就是針對該task 內部進行操作了。
任務棧的設計是爲了提高用戶體驗,但是也有其不足的地方。任務棧的缺點如下:
1、每開啓一次頁面都會在任務棧中添加一個Activity,而只有任務棧中的Activity 全部清除出棧時,任務棧被銷燬,程序纔會退出,這樣的設計在某種程度上可能造成了用戶體驗差,需要點擊多次返回纔可以把程序退出了。
2、每開啓一次頁面都會在任務棧中添加一個Activity 還會造成數據冗餘, 重複數據太多, 會導致內存溢出的問題(OOM)。
Andriod給出的官方圖:
爲了解決任務棧產生的問題,Android 爲Activity 設計了啓動模式,那麼下面的內容將介紹Android 中Activity 的啓動模式,這也是最重要的內容之一。
Activity 的啓動模式
啓動模式(launchMode)在多個Activity 跳轉的過程中扮演着重要的角色,它可以決定是否生成新的Activity 實例,是否重用已存在的Activity 實例,是否和其他Activity 實例共用一個task。
Activity 一共有以下四種launchMode:standard、singleTop、singleTask、singleInstance。我們可以在AndroidManifest.xml配置<activity>的android:launchMode 屬性爲以上四種之一即可。
l standard:標準啓動模式
特點:默認啓動模式, 每次激活Activity時(startActivity),都創建Activity實例,並放入任務棧.
l singleTop:單一頂部模式
特點:如果activity已經被開啓,而且是在棧頂,就不會在創建當前這個activity的實例,而是複用這個已經開啓的activity,但是如果不是在棧頂,就會初始化一個新的實例,在整個棧裏允許有多個實例
l singleTask:單一任務棧
特點:當前棧裏只允許有一個當前activity的實例,如果要開啓的activity在棧裏存在,並且在底部,就會移除這個activity上面所有的activity
應用場景:如果這個activity非常消耗cpu和內存,建議把這個activity的啓動模式設置爲singleTask,瀏覽器的browserActivity 設置的就是
l singleinstance:單一實例
特點:整個手機操作系統只有一個實例,並且是單獨運行在自己的任務棧裏
應用場景:通話界面的activity
Note:
Activity的啓動模式是面試幾乎都會問到的一個知識點,也是很重要的一個知識點,在項目開發中經常會用到啓動模式來幫助我們解決一些比較難解決的bug,也可以幫助我們去優化一個項目的任務棧,防止界面太多導致卡頓和OOM。