1.Service簡介
服務(wù)是一個應(yīng)用程序組件,可以在后臺執(zhí)行長時間運行的操作蕴坪,不提供用戶界面锦庸。一個應(yīng)用程序組件可以啟動一個服務(wù)块蚌,它將繼續(xù)在后臺運行闰非,即使用戶切換到另一個應(yīng)用程序。此外峭范,一個組件可以綁定到一個服務(wù)與它交互财松,甚至執(zhí)行進程間通信(IPC)。例如纱控,一個服務(wù)可能處理網(wǎng)絡(luò)通信辆毡、播放音樂、計時操作或與一個內(nèi)容提供者交互甜害,都在后臺執(zhí)行舶掖。
2.Service的種類
- 按運行地點分類:
類別 | 區(qū)別 | 優(yōu)點 | 缺點 | 應(yīng)用 |
---|---|---|---|---|
本地服務(wù)(Local Service) | 該服務(wù)依附在主進程上 | 服務(wù)依附在主進程上而不是獨立的進程,這樣在一定程度上節(jié)約了資源尔店,另外Local服務(wù)因為是在同一進程因此不需要IPC眨攘,也不需要AIDL。相應(yīng)bindService會 方便很多嚣州。 |
主進程被Kill后鲫售,服務(wù)便會終止。 | 如:音樂播放器播放等不需要常駐的服務(wù)该肴。 |
遠程服務(wù)(Remote Service) | 該服務(wù)是獨立的進程 | 服務(wù)為獨立的進程情竹,對應(yīng)進程名格式為所在包名加上你指定的android:process 字符串。由于是獨立的進程匀哄,因此在Activity所在進程被Kill的時候秦效,該服務(wù)依然在運行雏蛮,不受其他進程影響,有利于為多個進程提供服務(wù)具有較高的靈活性阱州。 |
該服務(wù)是獨立的進程底扳,會占用一定資源,并且使用AIDL進行IPC稍微麻煩一點贡耽。 | 一些提供系統(tǒng)服務(wù)的Service衷模,這種Service是常駐的。 |
- 按運行類型分類:
類別 | 區(qū)別 | 應(yīng)用 |
---|---|---|
前臺服務(wù) | 會在通知欄顯示onGoing的 Notification | 當服務(wù)被終止的時候蒲赂,通知一欄的 Notification 也會消失阱冶,這樣對于用戶有一定的通知作用。常見的如音樂播放服務(wù)滥嘴。 |
后臺服務(wù) | 默認的服務(wù)即為后臺服務(wù)木蹬,即不會在通知一欄顯示 onGoing的 Notification。 | 當服務(wù)被終止的時候若皱,用戶是看不到效果的镊叁。某些不需要運行或終止提示的服務(wù),如天氣更新走触,日期同步晦譬,郵件同步等。 |
- 按使用方式分類:
類別 | 區(qū)別 |
---|---|
startService啟動的服務(wù) | 主要用于啟動一個服務(wù)執(zhí)行后臺任務(wù)互广,不進行通信敛腌。停止服務(wù)使用stopService。 |
bindService啟動的服務(wù) | 方法啟動的服務(wù)要進行通信惫皱。停止服務(wù)使用unbindService像樊。 |
同時使用startService、bindService 啟動的服務(wù) | 停止服務(wù)應(yīng)同時使用stopService與unbindService旅敷。 |
3.Service的生命周期
通過這個圖可以看到生棍,兩種啟動Service的方式以及他們的生命周期,bindService的不同之處在于當綁定的組件銷毀后媳谁,對應(yīng)的service也就被kill了涂滴。
-
被啟動的服務(wù)的生命周期
一個Service被使用startService
方法啟動,不管是否調(diào)用了bindService
(綁定服務(wù))或unbindService
(解除綁定服務(wù))到該Service韩脑,該Service都會在后臺運行并不受影響氢妈。
一個Service被使用startService
方法啟動多少次,onCreate方法只會調(diào)用一次段多,onStartCommand方法將會被調(diào)用多次(與startService
的次數(shù)一致)首量,且系統(tǒng)只會創(chuàng)建一個Service實例(結(jié)束該Service也只需要調(diào)用一次stopService
),該Service會一直在后臺運行,直至調(diào)用stopService
或調(diào)用自身的stopSelf
方法加缘。
注:在系統(tǒng)資源不足的情況下鸭叙,服務(wù)有可能被系統(tǒng)結(jié)束(kill);
被綁定的服務(wù)的生命周期
如果一個Service在某個Activity中被調(diào)用bindService
方法啟動拣宏,不論bindService
被調(diào)用幾次沈贝,Service的onCreate方法只會執(zhí)行一次,同時onStartCommand方法始終不會調(diào)用勋乾。
當建立連接后宋下,Service會一直運行,除非調(diào)用unbindService
來接觸綁定辑莫、斷開連接或調(diào)用該Service的Context不存在了(如Activity被Finish——即通過bindService
啟動的Service的生命周期依附于啟動它的Context)学歧,系統(tǒng)在這時會自動停止該Service。被啟動又被綁定的服務(wù)的生命周期
當一個Service在被啟動(startService
)的同時又被綁定(bindService
)各吨,該Service將會一直在后臺運行枝笨,并且不管調(diào)用幾次,onCreate方法始終只會調(diào)用一次揭蜒,onStartCommand的調(diào)用次數(shù)與startService
調(diào)用的次數(shù)一致(使用bindService
方法不會調(diào)用onStartCommand)横浑。同時,調(diào)用unBindService
將不會停止Service屉更,必須調(diào)用stopService
或Service自身的stopSelf
來停止服務(wù)徙融。
官方原文:
If you do allow your service to be started and bound,then when then service has been started,the System does not destory the service when all clients unbind.Instead,you must explicitly stop the service,by calling stopSelf()
or stopService()
.
如果你同意你的服務(wù)被開啟和綁定,然后當服務(wù)被開啟的時候偶垮,當所有的客戶端都解除對服務(wù)的綁定android操作系統(tǒng)也不會銷毀這個服務(wù)张咳,相反的你必須顯示的調(diào)用stopSelf()或者stopService()方法來停止服務(wù)。
什么情況下使用:
如果你想要與正在運行的Service取得聯(lián)系似舵,那么有兩種方法,一種是使用廣播葱峡,另外一種方法就是使用bindService來建立聯(lián)系砚哗,前者的缺點是如果交流較為頻繁,容易造成性能上的問題砰奕,并且BroadcastReceiver本身執(zhí)行代碼的時間是很短的(也許執(zhí)行到一半蛛芥,后面的代碼便不會執(zhí)行),而后者則沒有這些問題军援,因此我們肯定選擇使用bindService(這個時候你便同時在使用startService和bindService了仅淑,這在Activity中更新Service的某些運行狀態(tài)是相當有用的)。
-
當服務(wù)被停止時
當一個服務(wù)被終止(stopService
胸哥、stopSelf
涯竟、unbindService
)時,onDestory方法將會被調(diào)用——所以我們需要在該方法中清除一些工作(依附該Service生命周期的,如:停止在Service中創(chuàng)建并運行的線程)庐船。
特別注意:
1.在使用startService
方法啟動服務(wù)后银酬,一定要調(diào)用stopService
方法來停止該服務(wù)(同上,可以在Activity的onDestory中來停止服務(wù))筐钟;
2.在某處調(diào)用bindService
綁定Service的時候揩瞪,要在對應(yīng)的某處調(diào)用unbindService
來解除綁定(如在Activity中綁定了Service,可以在onDestory中來解除綁定——雖然綁定的Service會在Activity結(jié)束時自動解除篓冲、停止)李破;
3.如果同時使用startService
與bindService
方法啟動Service,需要終止該Service時壹将,要調(diào)用stopService
和unbindService
方法(unbindService
依附于啟動它的Context喷屋,startServicec
并不依附于啟動它的Context。如果先調(diào)用unbindService
瞭恰,這時服務(wù)并不會被終止屯曹,當調(diào)用stopService
后,服務(wù)才會被終止惊畏;如果先調(diào)用stopService
恶耽,服務(wù)也不會被終止,當調(diào)用unbindService
或者之前調(diào)用bindService
的Context不存在了(如Activity被finish掉了)服務(wù)才會自動停止)颜启;
4.當手機屏幕發(fā)生旋轉(zhuǎn)時偷俭,如果Activity設(shè)置的是自動旋轉(zhuǎn)的話,在旋轉(zhuǎn)的過程中缰盏,Activity會重新創(chuàng)建涌萤,那么之前通過bindService
建立的連接便會斷開(之前的Context不存在了),服務(wù)也會被自動停止口猜。
4.Service的使用
在新建一個Service后负溪,記得在AndroidManifest.xml中注冊Service,在application內(nèi)添加需要注冊的Service信息:
<service android:name=".service.PlayerService"
android:label="PlayerService"
android:exported="true" />
Service示例如下:
public class PlayerService extends Service{
@Override
public void onCreate() {
super.onCreate();
}
/**
* onBind 是 Service 的虛方法济炎,因此我們不得不實現(xiàn)它川抡。
* 返回 null,表示客服端不能建立到此服務(wù)的連接须尚。
*/
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
// 已取代onStart方法--onStart方法是在Android2.0之前的平臺使用的.
// 在2.0及其之后崖堤,則需重寫onStartCommand方法,同時耐床,舊的onStart方法則不會再被直接調(diào)用
// (外部調(diào)用onStartCommand密幔,而onStartCommand里會再調(diào)用 onStart。在2.0之后撩轰,
// 推薦覆蓋onStartCommand方法胯甩,而為了向前兼容昧廷,在onStartCommand依然會調(diào)用onStart方法。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
}
// IBinder是遠程對象的基本接口蜡豹,是為高性能而設(shè)計的輕量級遠程調(diào)用機制的核心部分麸粮。但它不僅用于遠程
// 調(diào)用,也用于進程內(nèi)調(diào)用镜廉。這個接口定義了與遠程對象交互的協(xié)議弄诲。
// 不要直接實現(xiàn)這個接口,而應(yīng)該從Binder派生娇唯。
// Binder類已實現(xiàn)了IBinder接口
class MyBinder extends Binder {
/**
* 獲取Service的方法
* @return 返回PlayerService
*/
public PlayerService getService(){
return PlayerService.this;
}
}
}
-
startService啟動服務(wù)
通過startService()
啟動的服務(wù)處于“啟動”狀態(tài)齐遵,一旦啟動,Service就在后臺運行塔插,即使啟動它的應(yīng)用組件已經(jīng)被銷毀了梗摇。通常started狀態(tài)的Service執(zhí)行單任務(wù)并且不返回任何結(jié)果給啟動者(如當下載或上傳一個文件,當這項操作完成時想许,Service應(yīng)該停止它本身)伶授,示例如下:
public class PlayerActivity extends Activity{
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, PlayerService.class);
startService(intent);// 啟動服務(wù)
}
@Override
protected void onDestroy() {
super.onDestroy();
stopService(intent);// 在退出Activity時停止該服務(wù)
}
}
-
bindService綁定服務(wù)
一個綁定的Service提供一個允許組件與Service交互的接口,可以發(fā)送請求流纹、獲取返回結(jié)果糜烹,還可以通過跨進程通信來交互(IPC)。綁定的Service只有當應(yīng)用組件綁定后才能運行漱凝,多個組件可以綁定一個Service疮蹦,當調(diào)用unbindService()
方法時,這個Service就會被銷毀了茸炒。 - Local(本地服務(wù))的綁定
public class PlayerActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, PlayerService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);//綁定目標Service
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);// 解除綁定愕乎,斷開連接
}
// 在Activity中,我們通過ServiceConnection接口來取得建立連接與連接意外丟失的回調(diào)
ServiceConnection serviceConnection = new ServiceConnection() { @Override
public void onServiceConnected(ComponentName name, IBinder service){
// 建立連接
// 獲取服務(wù)的操作對象
PlayerService.MyBinder binder = (PlayerService.MyBinder)service;
binder.getService();// 獲取到的Service即PlayerService
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 連接斷開
}
};
}
注
Service的onBind
如果返回null壁公,則調(diào)用bindService
會啟動Service感论,但不會連接上Service因此ServiceConnection.onServiceConnected不會被調(diào)用,但仍然需要使用unbindService
方法來斷開連接贮尖,這樣Service才會停止笛粘。
-
Remote(遠程服務(wù))的綁定
【Android】遠程服務(wù)(Remote Service)的使用 -
前臺服務(wù)的使用
請訪問【Android】Service前臺服務(wù)的使用
注
Service與Activity一樣都存在與當前進程的主線程中,所以湿硝,一些阻塞UI的操作(如在Service進行網(wǎng)絡(luò)請求等)不能放在Service里進行。如果在Service里進行一些耗CPU和耗時操作润努,可能會引發(fā)ANR警告关斜,這時應(yīng)用會彈出是強制關(guān)閉還是等待的對話框。所以铺浇,對Service的理解就是和Activity平級的痢畜,只不過是看不見的,在后臺運行的一個組件,這也是為什么和Activity同被說為Android的基本組件丁稀。
5. AndroidManifest.xml中Service元素常見屬性
- andorid:name
服務(wù)類名吼拥。可以是完整的包名+類名线衫。也可使用
.
代替包名凿可。
- adroid:exported
其他應(yīng)用能否訪問該服務(wù),如果不能授账,則只有本應(yīng)用或有相同用戶ID的應(yīng)用能訪問枯跑。默認為false。
- android:enabled
標識服務(wù)是否可以被系統(tǒng)實例化白热。true--系統(tǒng)默認啟動敛助,false--不啟動。(默認值為true)
- android:label
顯示給用戶的服務(wù)名稱屋确。如果沒有進行服務(wù)名稱的設(shè)置纳击,默認顯示服務(wù)的類名。
- android:process
服務(wù)所運行的進程名攻臀。默認是在當前進程下運行焕数,與包名一致。如果進行了設(shè)置茵烈,將會在包名后加上設(shè)置的集成名百匆。
如果名稱設(shè)置為冒號:
開頭,一個對應(yīng)用程序私有的新進程會在需要時和運行到這個進程時建立呜投。如果名稱為小寫字母開頭加匈,服務(wù)會在一個相同名字的全局進程運行,如果有權(quán)限這樣的話仑荐。這允許不同應(yīng)用程序的組件可以分享一個進程雕拼,減少了資源的使用。
- android:icon
服務(wù)的圖標粘招。
- android:permission
申請使用該服務(wù)的權(quán)限啥寇,如果沒有配置下相關(guān)權(quán)限,服務(wù)將不執(zhí)行洒扎,使用
startService()
辑甜、bindService()
方法將都得不到執(zhí)行。
6.Thread與Service的區(qū)別
- Thread的優(yōu)先級低于Service的優(yōu)先級袍冷,在系統(tǒng)資源緊張的情況下磷醋,優(yōu)先殺死前者;
- 在Thread啟動后胡诗,如果退出當前Activity邓线,則無法對已經(jīng)啟動的Thread進行操作淌友,而服務(wù)則可以——因此可以在服務(wù)中啟動Thread來解決該問題;
- Service可以進行跨進程訪問骇陈,而Thread不行震庭;
- 在應(yīng)用中,如果是長時間的在后臺運行你雌,而且不需要交互的情況下器联,使用Service;
- 同樣是在后臺運行,不需要交互的情況下匪蝙,如果只是完成某個任務(wù)主籍,之后就不需要運行,而且可能是多個任務(wù)逛球,需需要長時間運行的情況下使用Thread;
- 如果任務(wù)占用CPU時間多千元,資源大的情況下,要使用Thread颤绕。
-
拓展閱讀
Thread和Service應(yīng)用場合的區(qū)別
Android中Service與Thread的區(qū)別
android-Service和Thread的區(qū)別
7.Service系列拓展閱讀
【Android】Service前臺服務(wù)的使用
【Android】遠程服務(wù)(Remote Service)的使用