Service 作為android 四大組件之一丐怯,主要用于再后臺(tái)處理一些耗時(shí)的邏輯或者去執(zhí)行一些長(zhǎng)期運(yùn)行的任務(wù)。
一等脂、startService 和 bindService
1. 生命周期和啟動(dòng)方式:
1.1 啟動(dòng)
通過startService啟動(dòng)服務(wù)時(shí)娄帖,如果是第一次啟動(dòng),會(huì)調(diào)用onCreate->onStartCommand茫船,但是多次啟動(dòng)時(shí)不會(huì)再調(diào)用onCreate,只有onStartCommand會(huì)被調(diào)用多次扭屁。
通過bindService綁定服務(wù)時(shí)算谈,如果服務(wù)還未啟動(dòng),會(huì)調(diào)用onCreate->onBind料滥,創(chuàng)建并且綁定服務(wù)濒生,多次調(diào)用bindService并不會(huì)多次調(diào)用onBind(),除非是多個(gè)客戶端來綁定服務(wù)幔欧。
1.2 銷毀
如果組件通過調(diào)用 startService() 啟動(dòng)服務(wù)罪治,則服務(wù)將一直運(yùn)行,直到服務(wù)使用 stopSelf()自行停止運(yùn)行礁蔗,或由其他組件通過調(diào)用 stopService() 停止它為止觉义。無(wú)論服務(wù)被啟動(dòng)了多少次,只要調(diào)用一次stopService浴井,便可終止(不考慮被綁定過的情況)晒骇。
如果組件是通過調(diào)用 bindService()來創(chuàng)建服務(wù)(且未調(diào)用onStartCommand()),則服務(wù)只會(huì)在該組件與其綁定時(shí)運(yùn)行磺浙。一旦該服務(wù)與所有客戶端之間的綁定全部取消洪囤,系統(tǒng)便會(huì)銷毀它。
2. starService和bindService一起使用:
如果一個(gè)Service又被啟動(dòng)又被綁定撕氧,則該Service會(huì)一直在后臺(tái)運(yùn)行瘤缩。首先不管如何調(diào)用,onCreate始終只會(huì)調(diào)用一次伦泥。startService調(diào)用多少次剥啤,Service的onStartCommand方法便會(huì)調(diào)用多少次锦溪。Service的終止,需要unbindService和stopService同時(shí)調(diào)用才行府怯。不管startService與bindService的調(diào)用順序刻诊,如果先調(diào)用unbindService,此時(shí)服務(wù)不會(huì)自動(dòng)終止牺丙,再調(diào)用stopService之后则涯,服務(wù)才會(huì)終止;如果先調(diào)用stopService冲簿,此時(shí)服務(wù)也不會(huì)終止是整,再次調(diào)用unbindService或者之前調(diào)用bindService的Context不存在了 ,服務(wù)才會(huì)停止民假。
3. 使用場(chǎng)景:
startService 主要用于開啟服務(wù),例如后臺(tái)下載和播放音樂
bindService 主要為了使用服務(wù)中的一些功能或者與服務(wù)進(jìn)行交互
這2種模式不是完全分離的龙优。你可以可以綁定到一個(gè)通過startService()啟動(dòng)的服務(wù)羊异。如一個(gè)intent想要播放音樂,通過startService啟動(dòng)后臺(tái)播放音樂的service彤断。然后野舶,也許用戶想要操作播放器或者獲取當(dāng)前正在播放的樂曲的信息,一個(gè)activity就會(huì)通過bindService建立一個(gè)到此service的連接. 這種情況下 stopService() 在全部的連接關(guān)閉后才會(huì)真正停止service宰衙。
Tips:
- 服務(wù)的onCreate和onDestroy在一個(gè)生命周期中只會(huì)執(zhí)行一次
- service的stopself方法的功能是平道,當(dāng)完成所有功能之后,將service停掉
- Service中onRebind方法被調(diào)用的時(shí)機(jī)供炼,需要滿足2個(gè)條件:
(1)服務(wù)中onUnBind方法返回值為true
(2)服務(wù)對(duì)象被解綁后沒有被銷毀一屋,之后再次被綁定
2. onStartCommand的返回值:
請(qǐng)注意,onStartCommand() 方法必須返回整型數(shù)袋哼。整型數(shù)是一個(gè)值冀墨,用于描述系統(tǒng)應(yīng)該如何在服務(wù)終止的情況下繼續(xù)運(yùn)行服務(wù)(如上所述,IntentService 的默認(rèn)實(shí)現(xiàn)將為您處理這種情況涛贯,不過您可以對(duì)其進(jìn)行修改)诽嘉。從onStartCommand()返回的值必須是以下常量之一:
1. START_NOT_STICKY
如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù),則除非有掛起 Intent 要傳遞弟翘,否則系統(tǒng)不會(huì)重建服務(wù)虫腋。這是最安全的選項(xiàng),可以避免在不必要時(shí)以及應(yīng)用能夠輕松重啟所有未完成的作業(yè)時(shí)運(yùn)行服務(wù)稀余。
2. START_STICKY
如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù)悦冀,則會(huì)重建服務(wù)并調(diào)用 onStartCommand(),但不會(huì)重新傳遞最后一個(gè) Intent睛琳。相反雏门,除非有掛起 Intent 要啟動(dòng)服務(wù)(在這種情況下嘿歌,將傳遞這些 Intent ),否則系統(tǒng)會(huì)通過空 Intent 調(diào)用 onStartCommand()茁影。這適用于不執(zhí)行命令宙帝、但無(wú)限期運(yùn)行并等待作業(yè)的媒體播放器(或類似服務(wù))。
3. START_REDELIVER_INTENT
如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù)募闲,則會(huì)重建服務(wù)步脓,并通過傳遞給服務(wù)的最后一個(gè) Intent 調(diào)用 onStartCommand()。任何掛起 Intent 均依次傳遞浩螺。這適用于主動(dòng)執(zhí)行應(yīng)該立即恢復(fù)的作業(yè)(例如下載文件)的服務(wù)靴患。
二、前臺(tái)服務(wù)
Service幾乎都是在后臺(tái)運(yùn)行的要出,一直以來它都是默默地做著辛苦的工作鸳君。但是Service的系統(tǒng)優(yōu)先級(jí)還是比較低的,當(dāng)系統(tǒng)出現(xiàn)內(nèi)存不足情況時(shí)患蹂,就有可能會(huì)回收掉正在后臺(tái)運(yùn)行的Service或颊。如果你希望Service可以一直保持運(yùn)行狀態(tài),而不會(huì)由于系統(tǒng)內(nèi)存不足的原因?qū)е卤换厥沾冢涂梢钥紤]使用前臺(tái)Service囱挑。前臺(tái)Service和普通Service最大的區(qū)別就在于,它會(huì)一直有一個(gè)正在運(yùn)行的圖標(biāo)在系統(tǒng)的狀態(tài)欄顯示沼溜,下拉狀態(tài)欄后可以看到更加詳細(xì)的信息平挑,非常類似于通知的效果。當(dāng)然有時(shí)候你也可能不僅僅是為了防止Service被回收才使用前臺(tái)Service系草,有些項(xiàng)目由于特殊的需求會(huì)要求必須使用前臺(tái)Service通熄,比如說墨跡天氣。
Intent intent = new Intent(this, MainActivity.class);
//需要讓Activity運(yùn)行在新的任務(wù)棧中
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Notification.Builder builder = new Notification.Builder(this);
Notification notification = builder.setSmallIcon(R.mipmap.ic_launcher)
.setContentText("this is a notify")
.setContentTitle("notify!!!").setTicker("notify")
.setContentIntent(PendingIntent.
getActivity(ServiceB.this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT))
.build();
startForeground(1, notification);
Tips:
- startForeground讓服務(wù)變成前臺(tái)服務(wù)并顯示通知找都,這時(shí)必須要setSmallIcon棠隐,否則會(huì)顯示默認(rèn)的通知,不顯示自定義通知
- 如何讓服務(wù)一直存活 http://zhoujianghua.com/2015/07/28/black_technology_in_alipay/
三檐嚣、Service 和 Thread
之所以有不少人會(huì)把它們聯(lián)系起來助泽,主要就是因?yàn)镾ervice的后臺(tái)概念。Thread我們大家都知道嚎京,是用于開啟一個(gè)子線程嗡贺,在這里去執(zhí)行一些耗時(shí)操作就不會(huì)阻塞主線程的運(yùn)行。而Service我們最初理解的時(shí)候鞍帝,總會(huì)覺得它是用來處理一些后臺(tái)任務(wù)的诫睬,一些比較耗時(shí)的操作也可以放在這里運(yùn)行,這就會(huì)讓人產(chǎn)生混淆了帕涌。但其實(shí)Service其實(shí)是運(yùn)行在主線程里的摄凡,所以說service的主進(jìn)程中不能執(zhí)行耗時(shí)的任務(wù)续徽,需要另外啟動(dòng)線程執(zhí)行,例如IntentService的內(nèi)部就是使用了HandlerThread的實(shí)現(xiàn)亲澡。
四钦扭、IntentService
IntentService是Service 的子類,它使用工作線程逐一處理所有啟動(dòng)請(qǐng)求床绪。如果不要求服務(wù)同時(shí)處理多個(gè)請(qǐng)求客情,這是最好的選擇。只需實(shí)現(xiàn) onHandleIntent() 方法即可癞己,該方法會(huì)接收每個(gè)啟動(dòng)請(qǐng)求的Intent膀斋,能夠執(zhí)行后臺(tái)工作。由于大多數(shù)啟動(dòng)服務(wù)都不必同時(shí)處理多個(gè)請(qǐng)求痹雅,因此使用 IntentService 類實(shí)現(xiàn)服務(wù)也許是最好的選擇仰担。
IntentService的特點(diǎn):
- IntentService 會(huì)創(chuàng)建一個(gè)線程,來處理所有傳給onStartCommand()的Intent請(qǐng)求
- 創(chuàng)建一個(gè)請(qǐng)求隊(duì)列绩社,用于將 Intent 逐一傳遞給 onHandleIntent() 實(shí)現(xiàn)摔蓝,不必?fù)?dān)心多線程問題
- 在所有的請(qǐng)求執(zhí)行完畢后結(jié)束Service
- 提供 onBind() 的默認(rèn)實(shí)現(xiàn)(返回 null)
- 提供默認(rèn)的 onStartCommand() 實(shí)現(xiàn),將intent傳入等待隊(duì)列中铃将,然后到onHandleIntent()的實(shí)現(xiàn)。所以如果需要重寫onStartCommand() 方法一定要調(diào)用父類的實(shí)現(xiàn)哑梳。
Tips:
- IntentService是針對(duì)StarteService設(shè)計(jì)的劲阎,由于它默認(rèn)實(shí)現(xiàn)的onBind()方法返回值是null,所以不適合bindService()
- 多次startService請(qǐng)求執(zhí)行耗時(shí)任務(wù)鸠真,不會(huì)并發(fā)執(zhí)行onHandleIntent()方法悯仙,而是一個(gè)一個(gè)順序執(zhí)行。當(dāng)所有的任務(wù)執(zhí)行完成吠卷,IntentService會(huì)自動(dòng)銷毀
問題:onStartCommand的返回值的具體應(yīng)用場(chǎng)景锡垄?
Demo:
http://download.csdn.net/detail/time_traveller14/9886836
參考資料:
https://developer.android.com/guide/components/services.html
http://blog.csdn.net/guolin_blog/article/details/11952435