一:Activity:
Activity 是Android 四大組件之一球昨,用于展示界面烤蜕。Activity 中所有操作都與用戶密切相關,是一個負責與用戶交互的組件韵吨,它上面可以顯示一些控件也可以監(jiān)聽并處理用戶的事件匿垄。一個Activity 通常就是一個單獨的屏幕,Activity 之間通過Intent 進行通信学赛。
一年堆、關閉當前Activity
在Activity 中調用finish()方法即可關閉當前Activity。
二盏浇、啟動一個Activity 時獲取該Activity 銷毀時的返回值
如果想讓我們的MainActivity 打開ContactListActivity变丧,同時能夠獲取到ContactListActivity銷毀時返回的數(shù)據(jù), 那么就不能通過startActivity(Intent) 方法去啟動ContactListActivity了绢掰。必須使用startActivityForResult(Intent intent, int requestCode)方法痒蓬,該方法必須跟onActivityResult(int requestCode,int resultCode, Intent data)方法結合著使用才行,當MainActivity 啟動的ContactListActivity銷毀前滴劲,如果ContactListActivity調用了setResult(int resultCode, Intent data)方法攻晒,那么系統(tǒng)就會調用MainActivity 的onActivityResult()方法,同時將數(shù)據(jù)Intent 的形式傳遞過來班挖。
Activity 的生命周期
學到這里我們有必要對Activity 有一個全新的認識鲁捏。Activity 已經不能再簡單的認為就是一個普通的類,其生命周期就是類的加載萧芙,對象的的創(chuàng)建和對象的卸載那么簡單给梅。Activity 從創(chuàng)建到銷毀,整個生命周期是一個非常復雜的過程双揪,該過程由Android 系統(tǒng)負責維護动羽。
Activity 的3 種狀態(tài)
我們人類有嬰幼兒時期、青少年時期渔期、中老年時期运吓,Activity 一樣也有3 種狀態(tài):Resumed、Paused疯趟、Stopped拘哨,這三種狀態(tài)是Android 官方給出的,我們翻譯過來可以理解為:激活或運行狀態(tài)信峻、暫停狀態(tài)宅静、停止狀態(tài)。這3 種狀態(tài)的特點如下:
Resumed 狀態(tài):Activity 位于前端位置站欺,并且獲取到了用戶的焦點姨夹。也就是當前Activity 完全可見也可用纤垂。
注意:在Android 中目前只允許同時只能有一個Activity 位于前端位置。
Paused 狀態(tài):如果另外一個Activity 位于前端位置并且獲取了焦點磷账,但是該Activity 還依然可見峭沦,那么該Activity 就處于了Paused 狀態(tài)。比如如果另外一個Activity 雖然位于前端逃糟,但是是透明的或者沒有占滿整個屏幕吼鱼,那么就會出現(xiàn)上面的這種情況。位于Paused 狀態(tài)的Activity 依然是“存活”著的绰咽,但是如果系統(tǒng)內存極端的不足菇肃,那么就有可能被系統(tǒng)“殺死”以便釋放內存。
Stopped 狀態(tài):當另外一個Activity 完全將該Activity 遮蓋住的情況下取募,那么該Activity 就處于停止狀態(tài)了琐谤。位于停止狀態(tài)的Activity 依然“活著”,但是它已經對用戶完全不可見了玩敏,因此只要系統(tǒng)需要釋放內存就會將該Activity“殺死”斗忌。
我們編寫的代碼要根據(jù)Activity 的不同狀態(tài)讓其做不同的工作,比如如果我們的Activity 是用于播放視頻的旺聚,那么當其位于Resumed 狀態(tài)時我們可以讓視頻正常的播放织阳,當Activity 位于Paused 狀態(tài)的時候,我們也應該讓我們的視頻暫停播放砰粹,當Activity 位于Stopped 狀態(tài)時我們應該停止播放視頻并釋放資源唧躲。
那么如何讓我們的程序員能夠感知到Activity 的狀態(tài)變化呢?Android 系統(tǒng)為了將Activity 狀態(tài)的變化通知給我們在Activity 中提供了7 個回調方法碱璃。我們只需要在不同的回調方法中完成不同的工作即可弄痹。
Activity 生命周期的7 個回調方法
方法名
特點
OnCreate
當Activity 第一次創(chuàng)建時被調用,在該方法中我們應該執(zhí)行創(chuàng)建視圖厘贼、初始化數(shù)據(jù)等工作界酒。該方法被調用之后緊接著就是調用onStart 方法圣拄。
onStart
當Activity 對用戶可見前被系統(tǒng)調用嘴秸。
onResume
當Activity 可以跟用戶交互前被調用,該方法被調用后Activity 就處于Resumed 狀態(tài)庇谆。
onPause
當另外一個Activity 即將成為Resumed 狀態(tài)前調用岳掐,在該方法中應該保存臨時數(shù)據(jù)、停止動畫饭耳、暫停視頻播放器等串述。必須要注意的就是該方法執(zhí)行必須要快,因為只有當該方法執(zhí)行過之后寞肖,另外一個Activity 才會成為Resumed 狀態(tài)纲酗,不然會造成Activity 直接切換的“卡頓”現(xiàn)象衰腌。
onStop
當Activity 對用戶已經完全不可見的時候就會調用該方法。當另外一個Activity 已經成為Resumed 狀態(tài)或者當前Activity 被銷毀的情況下會導致當前Activity 不可見觅赊。
onDestory
當Activity 被銷毀前調用右蕊。當前Activity 調用finish()方法或者系統(tǒng)為了釋放內存而將其銷毀都會調用該方法。
onRestart
當Activity 處于onStop 狀態(tài)之后吮螺,如果重新啟動則會調用該方法饶囚。比如如果當前Activity位于Resumed 狀態(tài),此時我們按了Home 鍵鸠补,那么Activity 就完全不可見了萝风,onStop 方法就會被執(zhí)行,然后再長按Home 鍵再將該Activity 重新啟動起來就會調用onRestart 方法紫岩。
Activity 生命周期圖
下圖是Android官方給出的Activity 生命周期圖:
橫豎屏切換時Activity 的生命周期
Android 手機在橫豎屏切換時规惰,默認情況下會把Activity 先銷毀再創(chuàng)建,模擬器橫豎屏切換的快捷鍵是Ctrl+F11被因。
在類似手機游戲卿拴、手機影音這一類的應用中,這個體驗是非常差的梨与。不讓Activity 在橫豎屏切換時銷毀堕花,只需要在清單文件聲明Activity 時配置節(jié)點的幾個屬性即可,其方式如下:
一. 4.0 以下版本:
android:configChanges="orientation|keyboardHidden"
二. 4.0 以上版本:
android:configChanges="orientation|screenSize"
三. 4.0 以上版本:
android:configChanges="orientation|keyboardHidden|screenSize"
將該參數(shù)配置到Activity 中后再切換屏幕方向粥鞋,那么Activity 就不會再銷毀和重新創(chuàng)建了缘挽。但是配置了該參數(shù)僅僅是不讓Activity 銷毀和重建,Activity 界面依然會跟著屏幕方向重新調整呻粹,那么如何固定Activity 的方向呢壕曼?
固定Activity 的方向
想固定Activity 的方向其實比較簡單,有兩種方法:
1等浊、通過配置文件
在AndroidManifest.xml 中的activity 節(jié)點中添加如下屬性腮郊。
android:screenOrientation="portrait"
該屬性通常有兩個常量值,portrait:垂直方向筹燕,landscape:水平方向轧飞。
2、通過代碼
在Activity 的onCreate 方法中執(zhí)行如下方法撒踪。
//垂直方向
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
//水平方向
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
Activity 的啟動模式
Activity 的任務棧
Task Stack(任務棧)是一個具有棧結構的容器过咬,可以放置多個Activity 實例。啟動一個應用制妄,系統(tǒng)就會為之創(chuàng)建一個task掸绞,來放置根Activity;默認情況下耕捞,一個Activity 啟動另一個Activity 時衔掸,兩個Activity是放置在同一個task 中的烫幕,后者被壓入前者所在的task 棧,當用戶按下back 鍵敞映,后者從task 中被彈出纬霞,
前者又顯示在屏幕前,特別是啟動其他應用中的Activity 時驱显,兩個Activity 對用戶來說就好像是屬于同一個應用诗芜;系統(tǒng)task 和應用task 之間是互相獨立的,當我們運行一個應用時埃疫,按下Home 鍵回到主屏伏恐,啟動另一個應用,這個過程中栓霜,之前的task 被轉移到后臺翠桦,新的task 被轉移到前臺,其根Activity 也會顯示到
幕前胳蛮,過了一會之后销凑,再次按下Home 鍵回到主屏,再選擇之前的應用仅炊,之前的task 會被轉移到前臺斗幼,系統(tǒng)仍然保留著task 內的所有Activity 實例,而那個新的task 會被轉移到后臺抚垄,如果這時用戶再做后退等動作蜕窿,就是針對該task 內部進行操作了。
任務棧的設計是為了提高用戶體驗呆馁,但是也有其不足的地方桐经。任務棧的缺點如下:
1、每開啟一次頁面都會在任務棧中添加一個Activity浙滤,而只有任務棧中的Activity 全部清除出棧時阴挣,任務棧被銷毀,程序才會退出纺腊,這樣的設計在某種程度上可能造成了用戶體驗差畔咧,需要點擊多次返回才可以把程序退出了。
2摹菠、每開啟一次頁面都會在任務棧中添加一個Activity 還會造成數(shù)據(jù)冗余, 重復數(shù)據(jù)太多, 會導致內存溢出的問題(OOM)盒卸。
Andriod給出的官方圖:
為了解決任務棧產生的問題骗爆,Android 為Activity 設計了啟動模式次氨,那么下面的內容將介紹Android 中Activity 的啟動模式,這也是最重要的內容之一摘投。
Activity 的啟動模式
啟動模式(launchMode)在多個Activity 跳轉的過程中扮演著重要的角色煮寡,它可以決定是否生成新的Activity 實例虹蓄,是否重用已存在的Activity 實例,是否和其他Activity 實例共用一個task幸撕。
Activity 一共有以下四種launchMode:standard薇组、singleTop、singleTask坐儿、singleInstance律胀。我們可以在AndroidManifest.xml 配置的android:launchMode 屬性為以上四種之一即可。
standard: 標準啟動模式
特點:默認啟動模式, 每次激活Activity時(startActivity)貌矿,都創(chuàng)建Activity實例炭菌,并放入任務棧.
singleTop:單一頂部模式
特點:如果activity已經被開啟,而且是在棧頂逛漫,就不會在創(chuàng)建當前這個activity的實例黑低,而是復用這個已經開啟的activity,但是如果不是在棧頂酌毡,就會初始化一個新的實例克握,在整個棧里允許有多個實例
singleTask:單一任務棧
特點:當前棧里只允許有一個當前activity的實例,如果要開啟的activity在棧里存在枷踏,并且在底部菩暗,就會移除這個activity上面所有的activity
應用場景:如果這個activity非常消耗cpu和內存,建議把這個activity的啟動模式設置為singleTask旭蠕,瀏覽器的browserActivity 設置的就是
singleinstance:單一實例
特點:整個手機操作系統(tǒng)只有一個實例勋眯,并且是單獨運行在自己的任務棧里
應用場景:通話界面的activity
Note:
Activity的啟動模式是面試幾乎都會問到的一個知識點,也是很重要的一個知識點下梢,在項目開發(fā)中經常會用到啟動模式來幫助我們解決一些比較難解決的bug客蹋,也可以幫助我們去優(yōu)化一個項目的任務棧,防止界面太多導致卡頓和OOM孽江。
二:Broadcast:
在Android 中讶坯,Broadcast 是一種廣泛運用的在應用程序之間傳輸信息的機制。而BroadcastReceiver 是對發(fā)送出來的Broadcast 進行過濾接受并響應的一類組件岗屏,是Android 四大組件之一辆琅。
廣播接收者(BroadcastReceiver)用于接收廣播的,廣播的發(fā)送是通過調用sendBroadcast(Intent)/sendOrderedBroadcast(Intent)來實現(xiàn)的这刷。通常一個廣播可以被多個廣播接收者所接收婉烟。
廣播被分為兩種不同的類型:“普通廣播(Normal Broadcasts)”也叫無序廣播和“有序廣播(OrderedBroadcasts)”。
注意:如果我們的應用退出了暇屋,那么就無法監(jiān)聽到該廣播似袁,可能有人說是因為退出的時候調用了MainActivity 的onDestory()方法,而onDestory()方法中調用了unregisterReceiver(BroadCastReceiver)方法,確實如此的昙衅。那么如果我們將onDestory()方法中的unregisterReceiver()方法給去掉會是什么樣的情況呢扬霜?那我們就一起試一下吧!
將MainActivity.java 中的unregisterReceiver()去掉之后重新運行上面的項目而涉,然后點擊back 鍵著瓶,發(fā)現(xiàn)logcat 輸入了如下錯誤信息:
上面的信息說我們的MainActivity 導致了IntentReceiver 的泄露。ScreenReceiver 在MainActivity 中被注冊了但是當MainActivity 銷毀的時候沒有被反注冊啼县。
可見要想讓我們的代碼更加完善材原,必須在onDestory 中或者其他地方(必須保證Activity 銷毀前)將接收者給反注冊掉。
三:Serivce:
Serivce的基本概念
Android 官方文檔對Service 的解釋如下:
翻譯:
Service 是應用組件之一季眷,用來執(zhí)行需要長時間運行的操作华糖,Service 運行在后臺并且跟用戶沒有交互界面。第三方應用的組件(指四大組件的任意一種)可以啟動一個Service瘟裸,一旦啟動起來客叉,該Service 就一直在后臺運行,就算用戶已經將該應用置為后臺進程话告。另外兼搏,組件也可以通過綁定的形式跟一個Service
進行交互,甚至完成進程間通信沙郭。比如:Service 可以在后臺處理網絡傳輸佛呻、播放音樂、進行I/O 流的讀寫或者跟內容提供者進行交互病线。
Service 的特點如下:
Service 在Android 中是一種長生命周期的組件吓著,它不實現(xiàn)任何用戶界面,是一個沒有界面的Activity
Service 長期在后臺運行送挑,執(zhí)行不關乎界面的一些操作比如:網易新聞服務绑莺,每隔1 分鐘去服務查看是否有最新新聞
Service 和Thread 有點相似,但是使用Thread 不安全惕耕,不嚴謹
Service 和其他組件一樣纺裁,都是運行在主線程中,因此不能用它來做耗時的操作
Service 的生命周期回調函數(shù)
和Activity 一樣司澎,service 也有一系列的生命周期回調函數(shù)欺缘,你可以實現(xiàn)它們來監(jiān)測service 狀態(tài)的變化恐似,并且在適當?shù)臅r候執(zhí)行適當?shù)墓ぷ鳌?/p>
下面的service 展示了每一個生命周期的方法蝇棉,也是官網給出的demo:
注意:不同于Activity 的生命周期回調方法,Service 不須調用父類的生命周期回調方法仇参。
Service的生命周期圖
官方給出的Service 生命周期圖如下所示蛤铜。該圖左側展示的是用startService()方法啟動的Service的生命周期嫩絮,右側展示的是用bindService()方法啟動的Service 的生命周期丛肢。
這個圖說明了Service 典型的回調方法,盡管這個圖中將開啟的Service 和綁定的Service 分開絮记,但是我們需要記住,任何Service 都潛在地允許被綁定虐先。所以怨愤,一個被開啟的Service 仍然可能被綁定。實現(xiàn)這些方法蛹批,可以看到兩層嵌套的Service 的生命周期撰洗。
整體生命周期(The entire lifetime)
Service 整體的生命時間是從onCreate()被調用開始,到onDestroy()方法返回為止腐芍。和Activity 一樣差导,Service 在onCreate()中進行它的初始化工作,在onDestroy()中釋放殘留的資源猪勇。比如设褐,一個音樂播放service 可以在onCreate()中創(chuàng)建播放音樂的線程,在onDestory()中停止這個線程泣刹。
onCreate() 和onDestroy()會被所有的Service 調用助析,不論Service 是通過startService()還是bindService()建立的。
積極活動的生命周期(The active lifetime)
Service 積極活動的生命周期(active lifetime)是從onStartCommand() 或onBind()被調用開始椅您,它們各自處理由startService()或bindService()方法傳過來的Intent 對象外冀。如果service 是被開啟的,那么它的活動生命周期和整個生命周期一同結束掀泳。如果service 是被綁定的雪隧,它們它的活動生命周期是在onUnbind()方法返回后結束。
注意:
盡管一個被開啟的service 是通過調用stopSelf() 或stopService()來停止的员舵,沒有一個對應的回調函數(shù)與之對應脑沿,即沒有onStop()回調方法。所以马僻,當調用了停止的方法捅伤,除非這個service 和客戶組件綁定,否則系統(tǒng)將會直接銷毀它巫玻,onDestory()方法會被調用丛忆,并且是這個時候唯一會被調用的回調方法。
四:ContentProvider:
內容提供者ContentProvider仍秤,是Android 的四大組件之一熄诡。內容提供者是應用程序之間共享數(shù)據(jù)的接口。
Android 系統(tǒng)將這種機制應用到方方面面诗力,比如:聯(lián)系人(通訊錄應用程序)Provider 專為不同應用程序提供聯(lián)系人數(shù)據(jù)凰浮;短信(短信應用程序)Provider 專為不同應用程序提供系統(tǒng)短信信息我抠。當應用繼承ContentProvider 類,并重寫該類用于提供數(shù)據(jù)和存儲數(shù)據(jù)的方法袜茧,就可以向其他應用共享其數(shù)據(jù)菜拓。雖然使用其他方法也可以對外共享數(shù)據(jù),但數(shù)據(jù)訪問方式會因數(shù)據(jù)存儲的方式而不同笛厦,如:采用文件方式對外共享數(shù)據(jù)纳鼎,需要進行文件操作讀寫數(shù)據(jù);采用SharedPreferences 共享數(shù)據(jù)裳凸,需要使用SharedPreferences API 讀寫數(shù)據(jù)贱鄙。而使用ContentProvider 共享數(shù)據(jù)的好處是統(tǒng)一了數(shù)據(jù)訪問方式。