一兼贡、Service 簡介
很多情況下份招,一些與用戶很少需要產(chǎn)生交互的應用程序,我們一般讓它們在后臺運行就行了哩罪,而且在它們運行期間我們仍然能運行其他的應用授霸。為了處理這種后臺進程,Android 引入了 Service 的概念际插。
#??? Service 在 Android 中是一種長生命周期的組件碘耳,它不實現(xiàn)任何用戶界面,是一個沒有界面的 Activity
#? ? Service 長期在后臺運行, 執(zhí)行不關乎界面的一些操作比如: 網(wǎng)易新聞服務,每隔 1分鐘去服務查看是否有最新新聞
#? ? Service 和 Thread 有點相似,但是使用 Thread 不安全, 不嚴謹
#? ? Service 和其他組件一樣,都是運行在主線程中框弛,因此不能用它來做耗時的操作
二辛辨、Android 中的進程
1)Android 中進程的種類
進程優(yōu)先級由高到低,依次為:
? ? 1.Foreground process 前臺進程
? ? 2. Visible process 可視進程, 可以看見, 但不可以交互.
??? 3. Service process 服務進程
??? 4. Background process 后臺進程
??? 5. Empty process 空進程(當程序退出時, 進程沒有被銷毀, 而是變成了空進程)
2)進程的回收機制
??????? Android 系統(tǒng)有一套內存回收機制,會根據(jù)優(yōu)先級進行回收瑟枫。Android 系統(tǒng)會盡可能的維持程序的進程, 但是終究還是需要回收一些舊的進程節(jié)省內存提供給新的或者重要的進程使用斗搞。
#? 進程的回收順序是:從低到高
#? 當系統(tǒng)內存不夠用時, 會把空進程一個一個回收掉
# 當系統(tǒng)回收所有的完空進程不夠用時, 繼續(xù)向上回收后臺進程, 依次類推
#? 但是當回收服務, 可視, 前臺這三種進程時, 系統(tǒng)非必要情況下不會輕易回收, 如果需要回收掉這三種進程, 那么在系統(tǒng)內存夠用時, 會再給重新啟動進程;但是服務進程如果用戶手動的關閉服務, 這時服務不會再重啟了。
3)為什么用服務而不是線程
????? 進程中運行著線程慷妙, Android 應用程序剛啟動都會開啟一個進程給這個程序來使用僻焚。Android 一個應用程序把所有的界面關閉時, 進程這時還沒有被銷毀, 現(xiàn)在處于的是空進程狀態(tài),Thread 運行在空進程中, 很容易的被銷毀了。
?????? 服務不容易被銷毀, 如果非法狀態(tài)下被銷毀了, 系統(tǒng)會在內存夠用時, 重新啟動膝擂。
三虑啤、Service 的生命周期
service 的生命周期,從它被創(chuàng)建開始架馋,到它被銷毀為止狞山,可以有兩條不同的路徑。
被開啟的 service 通過其他組件調用 startService()被創(chuàng)建叉寂。這種 service 可以無限地運行下去萍启,必須調用 stopSelf()方法或者其他組件調用 stopService()方法來停止它。當service 被停止時办绝,系統(tǒng)會銷毀它伊约。A bound service (綁定模式)被綁定的 service 是當其他組件(一個客戶)調用 bindService()來創(chuàng)建的姚淆。客戶可以通過一個 IBinder 接口和 service 進行通信屡律‰绶辏客戶可以通過 unbindService()方法來關閉這 種連接。一個 service 可以同時和多個客戶綁定超埋,當多個客戶都解除綁定之后搏讶,系統(tǒng)會銷毀service。
Tips: Service 的這兩中生命周期并不是完全分開的霍殴。
也就是說媒惕,你可以和一個已經(jīng)調用了 startService()而被開啟的 service 進行綁定。比如来庭,一個后臺音樂 service 可能因調用 startService()方法而被開啟了妒蔚,稍后,可能用戶想要控制播放器或者得到一些當前歌曲的信息月弛, 可以通過 bindService()將一個 activity 和 service 綁定肴盏。 這種情況下, stopService()或 stopSelf()實際上并不能停止這個 service帽衙,除非所有的客戶都解除綁定菜皂。
Service? 的生命周期回調函數(shù)
和 activity 一樣,service 也有一系列的生命周期回調函數(shù)厉萝,你可以實現(xiàn)它們來監(jiān)測 service 狀態(tài)的變化恍飘,并且在適當?shù)臅r候執(zhí)行適當?shù)墓ぷ鳌?/p>
下面的 service 展示了每一個生命周期的方法:
這個圖說明了 service 典型的回調方法, 盡管這個圖中將開啟的 service 和綁定的service 分開谴垫,但是你需要記住章母,任何 service 都潛在地允許綁定。所以弹渔,一個被開啟的 service 仍然可能被綁定胳施。實現(xiàn)這些方法,你可以看到兩層嵌套的 service 的生命周期肢专。
積極活動的生命時間
service 積極活動的生命時間(active lifetime)是從 onStartCommand() 或onBind()被調用開始舞肆,它們各自處理由 startService()或 bindService()方法傳過來的 Intent 對象。
如果 service 是被開啟的博杖,那么它的活動生命周期和整個生命周期一同結束椿胯。
如果 service 是被綁定的,它們它的活動生命周期是在 onUnbind()方法返回后結束剃根。
Tips :盡管一個被開啟的 service 是通過調用 stopSelf() 或 stopService()來停止的哩盲,沒有一個對應的回調函數(shù)與之對應,即沒有 onStop()回調方法。所以廉油,當調用了停止的方法惠险,除非這個 service 和客戶組件綁定,否則系統(tǒng)將會直接銷毀它抒线,onDestory()方法會被調用班巩,并且是這個時候唯一會被調用的回調方法。
管理生命周期
當綁定 service 和所有客戶端解除綁定之后嘶炭,Android 系統(tǒng)將會銷毀它抱慌, (除非它同時被 onStartCommand()方法開啟)。因此眨猎,如果你的 service 是一個純粹的綁定 service抑进,那么你不需要管理它的生命周期。睡陪、
然而寺渗,如果你選擇實現(xiàn) onStartCommand()回調方法,那么你必須顯式地停止service宝穗,因為 service 此時被看做是開啟的户秤。這種情況下,service 會一直運行到它自己調用 stopSelf()或另一個組件調用 stopService()逮矛,不論它是否和客戶端綁定。
另外转砖,如果你的 service 被開啟并且接受綁定须鼎,那么當系統(tǒng)調用你的 onUnbind()方法時,如果想要在下次客戶端綁定時候接受一個 onRebind()的調用(而不是調用 onBind())府蔗,你可以選擇在 onUnbind()中返回 true晋控。onRebind()的返回值為 void,但是客戶端仍然在onServiceConnected()回調方法中得到 IBinder 對象姓赤。
四赡译、遠程服務調用實例
在 Android 平臺中,各個組件運行在自己的進程中不铆,他們之間是不能相互訪問的蝌焚,但是在程序之間是不可避免的要傳遞一些對象, 在進程之間相互通信誓斥。 ? ? 為了實現(xiàn)進程之間的相互通信只洒, Android采用了一種輕量級的實現(xiàn)方式RPC(Remote Procedure Call 遠程進程調用)來完成進程之間的通信,并且 Android 通過接口定義語言(Android Interface DefinitionLanguage ,AIDL)來生成兩個進程之間相互訪問的代碼劳坑,例如毕谴,你在 Activity 里的代碼需要訪問 Service 中的一個方法,那么就可以通過這種方式來實現(xiàn)了。
AIDL 是 Android 的一種接口描述語言; 編譯器可以通過 aidl 文件生成一段代碼涝开, 通過預先定義的接口達到兩個進程內部通信進程的目的. 如果需要在一個 Activity 中, 訪問另一個Service 中的某個對象, 需要先將對象轉化成 AIDL 可識別的參數(shù)(可能是多個參數(shù)), 然后使用 AIDL 來傳遞這些參數(shù), 在消息的接收端, 使用這些參數(shù)組裝成自己需要的對象循帐。
AIDL RPC 機制是通過接口來實現(xiàn)的,類似 Windows 中的 COM 或者 Corba舀武,但他是輕量級的惧浴, 客戶端和被調用實現(xiàn)之間是通過代理模式實現(xiàn)的, 代理類和被代理類實現(xiàn)同一個接口 IBinder 接口奕剃。
下面是案例-商城支付的步驟:
需求:分別創(chuàng)建兩個工程衷旅,模擬一個支付平臺,暫且叫支付寶纵朋,模擬一個商戶端柿顶,叫商戶。商戶可以調用支付寶發(fā)布的遠程服務進行收款操作操软。
1)新創(chuàng)建一個 Android 工程《支付寶》嘁锯。在 src 目錄下創(chuàng)建 com.share.alipay.aidl 包,然后在該包下創(chuàng)建 AlipayRemoteService.aidl 文件聂薪。在該文件中只聲明一個接口家乘,在接口里聲明一個方法
package com.share.alipay.aidl;
interface AlipayRemoteService{????????????????????????????????????????????????????????????????????????????????????????????
?????????? boolean forwardPayMoney(float money);
}
Tips:當該 aidl 文件創(chuàng)建好以后 ADT 會自動在 gen 目錄下創(chuàng)建對應的類。
2)在《支付寶》src 目錄下創(chuàng)建 com.share.alipay.service 包藏澳,在該包中新建一個Service仁锯,叫 AlipayService,該類實現(xiàn)付款功能翔悠。代碼清單如下:
3)在《支付寶》工程的 AndroidManifest.xml 中注冊該 AlipayService业崖。
4)創(chuàng)建一個新 Android 工程,名字叫《商戶》蓄愁,包名:com.share.shop双炕。使用默認的布局文件和默認的 MainActivity 類。
將《支付寶》工程中的 AlipayRemoteService.aidl 文件拷貝到《商戶》工程的 src 目錄下撮抓,同時注意添加對應的包名妇斤,要求包名必須跟該文件在原工程中的包名嚴格一致。
5)編輯 activity_main.xm 布局文件丹拯。
6)編寫 MainActivity 類站超,在該類中實現(xiàn)核心方法。
7)先將《支付寶》部署到模擬器咽笼,然后將《商戶》部署到模擬器顷编,然后在《商戶》界面輸入一個金額, 然后點擊確定支付剑刑, 發(fā)現(xiàn) 《商戶》 工程已經(jīng)成功通過遠程服務調用了 《支付寶》中的服務媳纬。