Service小結(jié)

一、簡(jiǎn)介

Service 是一個(gè)可以在后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行操作而不使用用戶界面的應(yīng)用組件。服務(wù)可由其他應(yīng)用組件啟動(dòng)童叠,而且即使用戶切換到其他應(yīng)用,服務(wù)仍將在后臺(tái)繼續(xù)運(yùn)行课幕。 此外厦坛,組件可以綁定到服務(wù)五垮,以與之進(jìn)行交互,甚至是執(zhí)行進(jìn)程間通信 (IPC)杜秸。
注意:服務(wù)在其托管進(jìn)程的主線程中運(yùn)行放仗,它既不創(chuàng)建自己的線程,也不在單獨(dú)的進(jìn)程中運(yùn)行(除非另行指定)撬碟。

二诞挨、AndroidManifest配置

使用Service必須在AndroidManifest中注冊(cè),如下:
<code><manifest ... >
...
<application ... >
<service android:name=".ExampleService" />
</application>
</manifest></code>
可以為service配置一些特定屬性呢蛤。
<code><service android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:icon="drawable resource"
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
</service></code>
android:name:屬性是唯一必需的屬性亭姥,用于指定服務(wù)的類名。
android:enabled:是否可被系統(tǒng)實(shí)例化顾稀,默認(rèn)true.
android:exported : 設(shè)為false則其它應(yīng)用(user ID不同)無(wú)法啟動(dòng)此服務(wù)达罗。默認(rèn)true。
android:permission:指定啟動(dòng)服務(wù)及其運(yùn)行所在進(jìn)程所需的權(quán)限静秆。
android:process:指定服務(wù)運(yùn)行進(jìn)程粮揉,默認(rèn)當(dāng)前應(yīng)用進(jìn)程。
注意:Android5.0以后禁止了隱式聲明Intent來(lái)啟動(dòng)Service抚笔》鋈希可以通過setPackage()解決或者把一個(gè)隱式Intent轉(zhuǎn)換成顯式Intent。

三殊橙、Service的生命周期

service_lifecycle.png

<code>public class ExampleService extends Service {
int mStartMode; // 聲明服務(wù)如果被系統(tǒng)回收之后的行為
IBinder mBinder; // 返回的用于和Service交互的Binder
boolean mAllowRebind; // 聲明onRebind是否被使用
@Override
public void onCreate() {
// 服務(wù)正被創(chuàng)建
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 由于調(diào)用了startService()辐宾,服務(wù)正在啟動(dòng)
// 返回值表明了服務(wù)如果被系統(tǒng)回收之后的行為
// 返回值START_NOT_STICKY
// 返回值START_STICKY
// 返回值START_REDELIVER_INTENT
return mStartMode;
}
@Override
public IBinder onBind(Intent intent) {
// 由于調(diào)用了bindService(),服務(wù)正在綁定
// 返回Binder
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// 服務(wù)的所有綁定都調(diào)用了unbindService()
// 返回值決定是否允許調(diào)用onRebind
return mAllowRebind;
}
@Override
public void onRebind(Intent intent) {
//調(diào)用了onUnbind并返回true,再次調(diào)用bindService()
}
@Override
public void onDestroy() {
//服務(wù)被銷毀
}
}</code>
對(duì)于長(zhǎng)時(shí)間運(yùn)行的服務(wù)膨蛮,系統(tǒng)會(huì)隨著時(shí)間的推移降低服務(wù)在后臺(tái)任務(wù)列表中的位置叠纹,而服務(wù)也將隨之變得非常容易被終止。當(dāng)內(nèi)存過低且必須回收系統(tǒng)資源以供具有用戶焦點(diǎn)的 Activity 使用時(shí)敞葛,Android 系統(tǒng)就會(huì)強(qiáng)制停止服務(wù)誉察。
如果將服務(wù)綁定到具有用戶焦點(diǎn)的 Activity,則它不太可能會(huì)終止惹谐;
如果將服務(wù)聲明為前臺(tái)服務(wù)持偏,則它幾乎永遠(yuǎn)不會(huì)終止。
如果服務(wù)是啟動(dòng)服務(wù)氨肌,則您必須將其設(shè)計(jì)為能夠妥善處理系統(tǒng)對(duì)它的重啟鸿秆。因?yàn)槿绻到y(tǒng)終止服務(wù),那么一旦資源變得再次可用怎囚,系統(tǒng)便會(huì)重啟服務(wù)卿叽。

四、IntentService

IntentService是Service的子類,創(chuàng)建了默認(rèn)線程附帽,使用者只需實(shí)現(xiàn)onHandleIntent()即可埠戳,IntentService具體執(zhí)行操作如下:
1.創(chuàng)建默認(rèn)的工作線程,用于在應(yīng)用的主線程外執(zhí)行傳遞給onStartCommand()的所有 Intent蕉扮。
2.創(chuàng)建工作隊(duì)列整胃,用于將一個(gè) Intent 逐一傳遞給onHandleIntent()實(shí)現(xiàn),這樣您就永遠(yuǎn)不必?fù)?dān)心多線程問題喳钟。
3.在處理完所有啟動(dòng)請(qǐng)求后停止服務(wù)屁使,因此您永遠(yuǎn)不必調(diào)用stopSelf()。
4.提供onBind()的默認(rèn)實(shí)現(xiàn)(返回 null)。
5.提供onStartCommand()的默認(rèn)實(shí)現(xiàn),可將Intent 依次發(fā)送到工作隊(duì)列和onHandleIntent()實(shí)現(xiàn)沟优。
代碼實(shí)現(xiàn):
<code>public class TestIntentService extends IntentService {
// 必須實(shí)現(xiàn)的構(gòu)造函數(shù)
//且需要調(diào)用父類的構(gòu)造函數(shù),傳入的參數(shù)就是創(chuàng)建的工作線程的名字
public TestIntentService() {
super("word_thread_name");
}
//唯一要實(shí)現(xiàn)的方法燃箭,方法返回則服務(wù)停止
@Override
protected void onHandleIntent(Intent intent) {
}</code>

五筛谚、startService

5.1簡(jiǎn)介

啟動(dòng)服務(wù):startService(Intent intent)
停止服務(wù):stopService(Intent intent);
如果組件通過調(diào)用startService()啟動(dòng)服務(wù)(這會(huì)導(dǎo)致對(duì)onStartCommand()
的調(diào)用),則服務(wù)將一直運(yùn)行,直到服務(wù)使用stopSelf()自行停止運(yùn)行,或由其他組件Intent會(huì)重新傳遞給Service范抓。

5.2 創(chuàng)建一個(gè)Service

<code>public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
HandlerThread thread = new HandlerThread("name");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
}
}</code>
每次startService都會(huì)回調(diào)onStartCommand方法。在這個(gè)方法中食铐,我們擁有在運(yùn)行Service時(shí)傳遞進(jìn)來(lái)的Intent匕垫,這樣就可以與Service交換一些信息。這個(gè)方法需要返回一個(gè)整型值虐呻。這個(gè)整型代表系統(tǒng)應(yīng)該怎么樣處理這個(gè)Service:
START_STICKY:使用這個(gè)返回值象泵,如果系統(tǒng)殺死我們的Service將會(huì)重新創(chuàng)建。但是斟叼,發(fā)送給Service的Intent不會(huì)再投遞偶惠。這樣Service是一直運(yùn)行的。
START_NOT_STICKY:如果系統(tǒng)殺死了Service犁柜,不會(huì)重新創(chuàng)建洲鸠,除非客戶端顯式地調(diào)用了onStart命令。
START_REDELIVER_INTENT:功能與START_STICKY類似馋缅。另外,在這種情況下

5.3 前臺(tái)運(yùn)行服務(wù)

前臺(tái)服務(wù)被認(rèn)為是用戶主動(dòng)意識(shí)到的一種服務(wù)绢淀,因此在內(nèi)存不足時(shí)萤悴,系統(tǒng)也不會(huì)考慮將其終止。
通過調(diào)用startForeground()設(shè)置服務(wù)為前臺(tái)服務(wù)皆的,代碼如下:
<code>Intent notificationIntent = new Intent(this, ServiceActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_launcher) .setWhen(System.currentTimeMillis())
.setContentText("content")
.setContentTitle("title")
.setContentIntent(pendingIntent)
.build();
startForeground(1111, notification);</code>
注意:前臺(tái)服務(wù)必須為狀態(tài)欄提供通知覆履,狀態(tài)欄位于“正在進(jìn)行”標(biāo)題下方,這意味著除非服務(wù)停止或從前臺(tái)刪除,否則不能清除通知硝全。

5.4 向用戶發(fā)送通知

服務(wù)可以發(fā)送Toast通知和狀態(tài)欄通知兩種栖雾。

六、bindService

6.1簡(jiǎn)介

綁定服務(wù):bindService(Intent intent,ServiceConnection conn,int flags)
解除綁定:unbindService(ServiceConnection conn)
如果組件是通過調(diào)用bindService()來(lái)創(chuàng)建服務(wù)伟众,則服務(wù)只會(huì)在該組件與其綁定時(shí)運(yùn)行析藕。一旦該服務(wù)與所有客戶端之間的綁定全部取消,系統(tǒng)便會(huì)銷毀它凳厢。

6.2綁定Service

要想綁定服務(wù)账胧,必須:
1.實(shí)現(xiàn) ServiceConnection。
重寫兩個(gè)回調(diào)方法:
onServiceConnected()
綁定時(shí)調(diào)用先紫,傳遞onBind()的返回值治泥。
onServiceDisconnected()
當(dāng)服務(wù)的連接意外中斷時(shí)(例如當(dāng)服務(wù)崩潰或被終止時(shí))調(diào)用該方法。注意:取消綁定時(shí)并不會(huì)調(diào)用遮精。
2.調(diào)用 bindService()
傳遞ServiceConnection對(duì)象
3.調(diào)用 unbindService()取消綁定居夹。
注意:當(dāng)Activity被銷毀時(shí),會(huì)取消與服務(wù)的綁定本冲。但您應(yīng)該始終在完成與服務(wù)的交互時(shí)或您的 Activity 暫停時(shí)取消綁定吮播,以便服務(wù)能夠在未被占用時(shí)關(guān)閉。

6.3擴(kuò)展Binder

如果服務(wù)是自有應(yīng)用專用眼俊,并且在相同的進(jìn)程中運(yùn)行意狠,則應(yīng)通過擴(kuò)展 Binder 類并從onBind() 返回它的一個(gè)實(shí)例來(lái)創(chuàng)建接口。
以下是具體的設(shè)置方法:
1 在您的服務(wù)中疮胖,創(chuàng)建一個(gè)可滿足下列任一要求的Binder實(shí)例:
包含可調(diào)用的公共方法
返回當(dāng)前Service實(shí)例环戈,Service中包含可調(diào)用的公共方法
或返回由服務(wù)承載的其他類的實(shí)例,其中包含可調(diào)用的公共方法
2.從onBind()回調(diào)方法返回此Binder實(shí)例澎灸。
3.從onServiceConnected()回調(diào)方法中接收Binder

注意:之所以要求服務(wù)和客戶端必須在同一應(yīng)用內(nèi)院塞,是為了便于客戶端轉(zhuǎn)換返回的對(duì)象和正確調(diào)用其 API。服務(wù)和客戶端還必須在同一進(jìn)程內(nèi)性昭,因?yàn)榇朔椒ú荒苋魏慰邕M(jìn)程執(zhí)行拦止。如果服務(wù)只是您的自有應(yīng)用的后臺(tái)工作線程,則優(yōu)先采用這種方法糜颠。 不以這種方式創(chuàng)建接口的唯一原因是汹族,您的服務(wù)被其他應(yīng)用或不同的進(jìn)程占用。

6.4使用Messenger

如需讓接口跨不同的進(jìn)程工作其兴,則可使用 Messenger 為服務(wù)創(chuàng)建接口顶瞒。服務(wù)可以這種方式定義對(duì)應(yīng)于不同類型 Message 對(duì)象的 Handler。此 Handler 是 Messenger 的基礎(chǔ)元旬,后者隨后可與客戶端分享一個(gè)IBinder榴徐,從而讓客戶端能利用 Message 對(duì)象向服務(wù)發(fā)送命令守问。此外,客戶端還可定義自有Messenger坑资,以便服務(wù)回傳消息耗帕。
以下是具體步驟:
1.服務(wù)實(shí)現(xiàn)一個(gè) Handler,由其接收來(lái)自客戶端的每個(gè)調(diào)用的回調(diào)
2.Handler 用于創(chuàng)建 Messenger 對(duì)象(對(duì) Handler 的引用)
3.Messenger 創(chuàng)建一個(gè) IBinder袱贮,服務(wù)通過 onBind() 使其返回客戶端
4.客戶端使用 IBinder 將 Messenger(引用服務(wù)的 Handler)實(shí)例化仿便,然后使用后者將 Message 對(duì)象發(fā)送給服務(wù)
5.服務(wù)在其 Handler 中(具體地講,是在 handleMessage() 方法中)接收每個(gè) Message
<code>public class MessageService extends Service {
private Messenger message = new Messenger(new MesHandler());
@Override
public IBinder onBind(Intent intent) {
return message.getBinder();
}
class MesHandler extends Handler{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
}</code>
這是執(zhí)行進(jìn)程間通信 (IPC) 的最簡(jiǎn)單方法字柠,因?yàn)?Messenger 會(huì)在單一線程中創(chuàng)建包含所有請(qǐng)求的隊(duì)列探越,這樣您就不必對(duì)服務(wù)進(jìn)行線程安全設(shè)計(jì)。

6.5使用AIDL

如需直接使用 AIDL窑业,您必須創(chuàng)建一個(gè)定義編程接口的 .aidl 文件钦幔。Android SDK 工具利用該文件生成一個(gè)實(shí)現(xiàn)接口并處理 IPC 的抽象類,您隨后可在服務(wù)內(nèi)對(duì)其進(jìn)行擴(kuò)展常柄。
之前采用 Messenger 的方法實(shí)際上是以 AIDL 作為其底層結(jié)構(gòu)鲤氢。Messenger 會(huì)在單一線程中創(chuàng)建包含所有客戶端請(qǐng)求的隊(duì)列,以便服務(wù)一次接收一個(gè)請(qǐng)求西潘。不過卷玉,如果您想讓服務(wù)同時(shí)處理多個(gè)請(qǐng)求,則可直接使用 AIDL喷市。 在此情況下相种,您的服務(wù)必須具備多線程處理能力,并采用線程安全式設(shè)計(jì)品姓。

6.6注意事項(xiàng)

1.應(yīng)該始終捕獲 DeadObjectException 異常寝并,它是在連接中斷時(shí)引發(fā)的,也是遠(yuǎn)程方法引發(fā)的唯一異常
2.對(duì)象是跨進(jìn)程計(jì)數(shù)的引用
3.通常應(yīng)配對(duì)綁定和取消綁定腹备。
例如:在 onStart() 綁定衬潦, onStop() 取消綁定≈菜郑或者在 onCreate() 綁定镀岛,onDestroy() 取消綁定。
4.通常情況下友驮,切勿在 Activity 的 onResume() 和 onPause() 期間綁定和取消綁定漂羊,因?yàn)槊恳淮紊芷谵D(zhuǎn)換都會(huì)發(fā)生這些回調(diào),您應(yīng)該使發(fā)生在這些轉(zhuǎn)換期間的處理保持在最低水平喊儡。
5.此外拨与,如果您的應(yīng)用內(nèi)的多個(gè) Activity 綁定到同一服務(wù),并且其中兩個(gè) Activity 之間發(fā)生了轉(zhuǎn)換艾猜,則如果當(dāng)前 Activity 在下一次綁定(恢復(fù)期間)之前取消綁定(暫停期間)买喧,系統(tǒng)可能會(huì)銷毀服務(wù)并重建服務(wù)。 (Activity文檔中介紹了這種有關(guān) Activity 如何協(xié)調(diào)其生命周期的 Activity 轉(zhuǎn)換匆赃。)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末淤毛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子算柳,更是在濱河造成了極大的恐慌低淡,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞬项,死亡現(xiàn)場(chǎng)離奇詭異蔗蹋,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)囱淋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門猪杭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人妥衣,你說(shuō)我怎么就攤上這事皂吮。” “怎么了税手?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵蜂筹,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我芦倒,道長(zhǎng)艺挪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任兵扬,我火速辦了婚禮麻裳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘周霉。我一直安慰自己掂器,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布俱箱。 她就那樣靜靜地躺著国瓮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狞谱。 梳的紋絲不亂的頭發(fā)上乃摹,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音跟衅,去河邊找鬼孵睬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛伶跷,可吹牛的內(nèi)容都是我干的掰读。 我是一名探鬼主播秘狞,決...
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蹈集!你這毒婦竟也來(lái)了烁试?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤拢肆,失蹤者是張志新(化名)和其女友劉穎减响,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體郭怪,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡支示,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鄙才。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颂鸿。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖咒循,靈堂內(nèi)的尸體忽然破棺而出据途,到底是詐尸還是另有隱情,我是刑警寧澤叙甸,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布颖医,位于F島的核電站,受9級(jí)特大地震影響裆蒸,放射性物質(zhì)發(fā)生泄漏熔萧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一僚祷、第九天 我趴在偏房一處隱蔽的房頂上張望佛致。 院中可真熱鬧,春花似錦辙谜、人聲如沸俺榆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)罐脊。三九已至,卻和暖如春蜕琴,著一層夾襖步出監(jiān)牢的瞬間萍桌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工凌简, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留上炎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓雏搂,卻偏偏與公主長(zhǎng)得像藕施,于是被迫代替她去往敵國(guó)和親寇损。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 上篇我們講解了Android中的5中等級(jí)的進(jìn)程铅碍,分別是:前臺(tái)進(jìn)程润绵、可見進(jìn)程线椰、服務(wù)進(jìn)程胞谈、后臺(tái)進(jìn)程、空進(jìn)程憨愉。系統(tǒng)會(huì)按照...
    徐愛卿閱讀 3,857評(píng)論 6 33
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理烦绳,服務(wù)發(fā)現(xiàn),斷路器配紫,智...
    卡卡羅2017閱讀 134,656評(píng)論 18 139
  • 什么是Service Service是一個(gè)可以在后臺(tái)長(zhǎng)時(shí)間執(zhí)行的應(yīng)用組件径密。 Service的啟動(dòng)方式 startS...
    MGLEE閱讀 361評(píng)論 0 0
  • 目錄 Service 介紹 Service兩種啟動(dòng)方式 使用 測(cè)試 IntentService Activity與...
    gaaaaaaaaaao閱讀 1,674評(píng)論 0 4
  • 輾轉(zhuǎn)又到了陽(yáng)春三月。 這樣的時(shí)節(jié)躺孝,適合去踏青享扔。于是選一個(gè)陽(yáng)光麗日,一個(gè)人信步前行植袍,不用去遠(yuǎn)方惧眠,也不用背負(fù)行囊,只許...
    請(qǐng)叫我想念熊閱讀 394評(píng)論 1 5