一、介紹
Service(服務(wù))一個(gè)運(yùn)行在后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行的操作組件,它不提供任何用戶界面,作為與Activity同級(jí)的組件,它依舊是運(yùn)行在主線程中。
其它組件可以啟動(dòng)一個(gè)Service,當(dāng)這個(gè)Service啟動(dòng)之后便會(huì)在后臺(tái)執(zhí)行,這里需要注意,由于是在主線程中,所以我們需要另外開(kāi)啟一個(gè)線程來(lái)執(zhí)行我們的耗時(shí)操作。
此外,一個(gè)組件還可以與一個(gè)Service進(jìn)行綁定來(lái)實(shí)現(xiàn)組件之間的交互,甚至可以執(zhí)行IPC(Inter-Process Communication)進(jìn)程間通信。
Service可以在后臺(tái)執(zhí)行很多任務(wù),比如處理網(wǎng)絡(luò)事務(wù),播放音樂(lè),文件讀寫(xiě)或者與一個(gè)內(nèi)容提供者交互,等等。
二、服務(wù)分類
本地服務(wù)(Local)
該服務(wù)依附在主進(jìn)程上而不是獨(dú)立的進(jìn)程,這樣在一定程度上節(jié)約了資源,另外本地服務(wù)因?yàn)槭窃谕贿M(jìn)程因此不需要IPC,也不需要AIDL。相應(yīng)bindService會(huì)方便很多,當(dāng)主進(jìn)程被Kill后,服務(wù)便會(huì)終止。一般使用在音樂(lè)播放器播放等不需要常駐的服務(wù)。
遠(yuǎn)程服務(wù)(Remote Service)
該服務(wù)是獨(dú)立的進(jìn)程,對(duì)應(yīng)進(jìn)程名格式為所在包名加上你指定的android:process字符串。一般定義方式 android:process=":service" 由于是獨(dú)立的進(jìn)程,因此在Activity所在進(jìn)程被Kill的時(shí)候,該服務(wù)依然在運(yùn)行,不受其他進(jìn)程影響,有利于為多個(gè)進(jìn)程提供服務(wù)具有較高的靈活性。由于是獨(dú)立的進(jìn)程,會(huì)占用一定資源,并且使用AIDL進(jìn)行IPC比較麻煩。一般用于系統(tǒng)的Service,這種Service是常駐的。
三、Service啟動(dòng)方式
startService啟動(dòng)的服務(wù)
用于啟動(dòng)一個(gè)服務(wù)執(zhí)行后臺(tái)任務(wù),不與組件進(jìn)行通信,停止服務(wù)使用stopService。 當(dāng)一個(gè)應(yīng)用組件比如activity通過(guò)調(diào)用startService()來(lái)啟動(dòng)一個(gè)服務(wù)的時(shí)候,服務(wù)便處于啟動(dòng)狀態(tài)。一旦啟動(dòng),服務(wù)可以在后臺(tái)無(wú)限期地運(yùn)行下去,即使當(dāng)啟動(dòng)它的組件已經(jīng)銷毀。通常情況下,一個(gè)啟動(dòng)的service執(zhí)行一個(gè)單一的操作并且不會(huì)返回任何結(jié)果給調(diào)用者。
bindService啟動(dòng)的服務(wù)
用于啟動(dòng)的服務(wù)需要進(jìn)行通信。停止服務(wù)使用unbindService。 當(dāng)一個(gè)應(yīng)用組件通過(guò)調(diào)用bindService()來(lái)與一個(gè)服務(wù)綁定時(shí),服務(wù)便處于綁定狀態(tài)。一個(gè)綁定的服務(wù)提供了一個(gè)客戶端-服務(wù)器端接口來(lái)允許組件與服務(wù)進(jìn)行交互,發(fā)送請(qǐng)求,得到結(jié)果甚至通過(guò)IPC進(jìn)程間通信來(lái)完成操作。只有當(dāng)其它組件與服務(wù)進(jìn)行綁定時(shí),服務(wù)才會(huì)處于綁定狀態(tài)。多個(gè)組件可以同時(shí)與服務(wù)綁定,但是當(dāng)他們?nèi)慷冀獬壎〞r(shí),服務(wù)就會(huì)銷毀。
四、服務(wù)的生命周期
1.StartService:
一個(gè)Service被使用startService方法啟動(dòng),不管是否調(diào)用了bindService(綁定服務(wù))或unbindService(解除綁定服務(wù))到該Service,該Service都會(huì)在后臺(tái)運(yùn)行并不受影響。一個(gè)Service被使用startService方法啟動(dòng)多少次,onCreate方法只會(huì)調(diào)用一次,onStartCommand方法將會(huì)被調(diào)用多次(與startService的次數(shù)一致),且系統(tǒng)只會(huì)創(chuàng)建一個(gè)Service實(shí)例(結(jié)束該Service也只需要調(diào)用一次stopService),該Service會(huì)一直在后臺(tái)運(yùn)行直至調(diào)用stopService或調(diào)用自身的stopSelf方法。
注:在系統(tǒng)資源不足的情況下,服務(wù)有可能被系統(tǒng)結(jié)束(kill);
2.BindService:
如果一個(gè)Service在某個(gè)Activity中被調(diào)用bindService方法啟動(dòng),不論bindService被調(diào)用幾次,Service的onCreate方法只會(huì)執(zhí)行一次,同時(shí)onStartCommand方法始終不會(huì)調(diào)用。當(dāng)建立連接后,Service會(huì)一直運(yùn)行,除非調(diào)用unbindService來(lái)接觸綁定、斷開(kāi)連接或調(diào)用該Service的Context不存在了(如Activity被Finish——即通過(guò)bindService啟動(dòng)的Service的生命周期依附于啟動(dòng)它的Context),系統(tǒng)在這時(shí)會(huì)自動(dòng)停止該Service。
3.StartService AND BindService:
當(dāng)一個(gè)Service在被啟動(dòng)(startService 的同時(shí)又被綁定(bindService ),該Service將會(huì)一直在后臺(tái)運(yùn)行,并且不管調(diào)用幾次,onCreate方法始終只會(huì)調(diào)用一次,onStartCommand的調(diào)用次數(shù)與startService 調(diào)用的次數(shù)一致(使用bindService 方法不會(huì)調(diào)用onStartCommand)。同時(shí),調(diào)用unBindService 將不會(huì)停止Service,必須調(diào)用stopService 或Service自身的stopSelf 來(lái)停止服務(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ù)被開(kāi)啟和綁定,然后當(dāng)服務(wù)被開(kāi)啟的時(shí)候,當(dāng)所有的客戶端都解除對(duì)服務(wù)的綁定android操作系統(tǒng)也不會(huì)銷毀這個(gè)服務(wù),相反的你必須顯示的調(diào)用stopSelf()或者stopService()方法來(lái)停止服務(wù)。
什么情況下使用:
如果你想要與正在運(yùn)行的Service取得聯(lián)系,那么有兩種方法,一種是使用廣播,另外一種方法就是使用bindService來(lái)建立聯(lián)系,前者的缺點(diǎn)是如果交流較為頻繁,容易造成性能上的問(wèn)題,并且BroadcastReceiver本身執(zhí)行代碼的時(shí)間是很短的(也許執(zhí)行到一半,后面的代碼便不會(huì)執(zhí)行),而后者則沒(méi)有這些問(wèn)題,因此我們肯定選擇使用bindService(這個(gè)時(shí)候你便同時(shí)在使用startService和bindService了,這在Activity中更新Service的某些運(yùn)行狀態(tài)是相當(dāng)有用的)。
4.停止Service:
當(dāng)一個(gè)服務(wù)被終止(stopService 、stopSelf 、unbindService )時(shí),onDestory方法將會(huì)被調(diào)用——所以我們需要在該方法中清除一些工作(依附該Service生命周期上的,比如:停止在Service中創(chuàng)建并運(yùn)行的線程)。
特別注意:
1.在使用startService 方法啟動(dòng)服務(wù)后,一定要調(diào)用stopService 方法來(lái)停止該服務(wù)(同上,可以在Activity的onDestory中來(lái)停止服務(wù));
2.在某處調(diào)用bindService 綁定Service的時(shí)候,要在對(duì)應(yīng)的某處調(diào)用 unbindService 來(lái)解除綁定(如在Activity中綁定了Service,可以在onDestory中來(lái)解除綁定——雖然綁定的Service會(huì)在Activity結(jié)束時(shí)自動(dòng)解除、停止);
3.如果同時(shí)使用startService 與bindService 方法啟動(dòng)Service,需要終止該Service時(shí),要調(diào)用stopService 和unbindService 方法(unbindService 依附于啟動(dòng)它的Context,startServicec 并不依附于啟動(dòng)它的Context。如果先調(diào)用unbindService ,這時(shí)服務(wù)并不會(huì)被終止,當(dāng)調(diào)用stopService 后,服務(wù)才會(huì)被終止;如果先調(diào)用stopService ,服務(wù)也不會(huì)被終止,當(dāng)調(diào)用unbindService 或者之前調(diào)用bindService 的Context不存在了(如Activity被finish掉了)服務(wù)才會(huì)自動(dòng)停止);
4.當(dāng)手機(jī)屏幕發(fā)生旋轉(zhuǎn)時(shí),如果Activity設(shè)置的是自動(dòng)旋轉(zhuǎn)的話,在旋轉(zhuǎn)的過(guò)程中,Activity會(huì)重新創(chuàng)建,那么之前通過(guò)bindService 建立的連接便會(huì)斷開(kāi)(之前的Context不存在了),服務(wù)也會(huì)被自動(dòng)停止。
五、Service使用
1.創(chuàng)建服務(wù)
public class MyService extends Service{
//服務(wù)創(chuàng)建
@Override
public void onCreate() {
super.onCreate();
}
// 服務(wù)啟動(dòng)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
//服務(wù)銷毀
@Override
public void onDestroy() {
stopSelf(); //自殺服務(wù)
super.onDestroy();
}
//綁定服務(wù)
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
// IBinder是遠(yuǎn)程對(duì)象的基本接口,是為高性能而設(shè)計(jì)的輕量級(jí)遠(yuǎn)程調(diào)用機(jī)制的核心部分。但它不僅用于遠(yuǎn)程
// 調(diào)用,也用于進(jìn)程內(nèi)調(diào)用。這個(gè)接口定義了與遠(yuǎn)程對(duì)象交互的協(xié)議。
// 不要直接實(shí)現(xiàn)這個(gè)接口,而應(yīng)該從Binder派生。
// Binder類已實(shí)現(xiàn)了IBinder接口
class MyBinder extends Binder {
/** * 獲取Service的方法 * @return 返回PlayerService */
public MyService getService(){
return MyService.this;
}
}
}
如果你才用的是 startService的方式那么 onBind方法可以忽略
2.注冊(cè)服務(wù)
<service
android:name=".service.MyService"
android:exported="true"
android:label="MyService" />
3.開(kāi)啟服務(wù)
start:
public class MyActivity extends AppCompatActivity{
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, MyService.class);
startService(intent);// 啟動(dòng)服務(wù)
}
@Override
protected void onDestroy() {
super.onDestroy();
stopService(intent);// 在退出Activity時(shí)停止該服務(wù),如果希望常駐后臺(tái),可以不進(jìn)行停止。
}
}
bind
public class MyActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//綁定目標(biāo)Service
Intent intent = new Intent(this, MyActivity.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);// 解除綁定,斷開(kāi)連接
}
// 在Activity中,我們通過(guò)ServiceConnection接口來(lái)取得建立連接與連接意外丟失的回調(diào)
ServiceConnection serviceConnection = new ServiceConnection() { @Override
public void onServiceConnected(ComponentName name, IBinder service){
// 建立連接
// 獲取服務(wù)的操作對(duì)象
MyService.MyBinder binder = (MyService.MyBinder)service;
binder.getService();// 獲取到的Service即MyService
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 連接斷開(kāi)
}
};
}
綁定服務(wù),一般涉及到組件或進(jìn)程之間的通信,既然需要通信,那么我們肯定需要一個(gè)連接,這里ServiceConnection就是我們所需要的連接,通過(guò)Ibinder的傳遞,我們可以獲取到Service的Ibinder對(duì)象,從而進(jìn)行相關(guān)操作。
六、粘性服務(wù)、非粘性服務(wù)
關(guān)于粘性服務(wù),這里需要提到 Service的onStartCommand返回值
START_STICKY:
sticky的意思是“粘性的”。使用這個(gè)返回值時(shí),我們啟動(dòng)的服務(wù)跟應(yīng)用程序"粘"在一起,如果在執(zhí)行完onStartCommand后,服務(wù)被異常kill掉,系統(tǒng)會(huì)自動(dòng)重啟該服務(wù)。當(dāng)再次啟動(dòng)服務(wù)時(shí),傳入的第一個(gè)參數(shù)將為null;
START_NOT_STICKY:
“非粘性的”。使用這個(gè)返回值時(shí),如果在執(zhí)行完onStartCommand后,服務(wù)被異常kill掉,系統(tǒng)不會(huì)自動(dòng)重啟該服務(wù)。
START_REDELIVER_INTENT:
重傳Intent。使用這個(gè)返回值時(shí),如果在執(zhí)行完onStartCommand后,服務(wù)被異常kill掉,系統(tǒng)會(huì)自動(dòng)重啟該服務(wù),并將Intent的值傳入。
七、AndroidManifest.xml中Service元素常見(jiàn)屬性
andorid:name
服務(wù)類名。可以是完整的包名+類名。也可使用. 代替包名。
adroid:exported
其他應(yīng)用能否訪問(wèn)該服務(wù),如果不能,則只有本應(yīng)用或有相同用戶ID的應(yīng)用能訪問(wèn)。默認(rèn)為false。
android:enabled
標(biāo)識(shí)服務(wù)是否可以被系統(tǒng)實(shí)例化。true--系統(tǒng)默認(rèn)啟動(dòng),false--不啟動(dòng)。(默認(rèn)值為true)
android:label
顯示給用戶的服務(wù)名稱。如果沒(méi)有進(jìn)行服務(wù)名稱的設(shè)置,默認(rèn)顯示服務(wù)的類名。
android:process
服務(wù)所運(yùn)行的進(jìn)程名。默認(rèn)是在當(dāng)前進(jìn)程下運(yùn)行,與包名一致。如果進(jìn)行了設(shè)置,將會(huì)在包名后加上設(shè)置的集成名。如果名稱設(shè)置為冒號(hào): 開(kāi)頭,一個(gè)對(duì)應(yīng)用程序私有的新進(jìn)程會(huì)在需要時(shí)和運(yùn)行到這個(gè)進(jìn)程時(shí)建立。如果名稱為小寫(xiě)字母開(kāi)頭,服務(wù)會(huì)在一個(gè)相同名字的全局進(jìn)程運(yùn)行,如果有權(quán)限這樣的話。這允許不同應(yīng)用程序的組件可以分享一個(gè)進(jìn)程,減少了資源的使用。
android:icon
服務(wù)的圖標(biāo)。
android:permission
申請(qǐng)使用該服務(wù)的權(quán)限,如果沒(méi)有配置下相關(guān)權(quán)限,服務(wù)將不執(zhí)行,使用startService() 、bindService() 方法將都得不到執(zhí)行。
關(guān)于服務(wù),當(dāng)我們?cè)趹?yīng)用開(kāi)發(fā)中,如果需要長(zhǎng)時(shí)間的在后臺(tái)運(yùn)行,獨(dú)立完成某一些事情的情況下,請(qǐng)使用Service!
此文綜合:http://www.lxweimin.com/p/1e49e93c3ec8 以及自己的一些問(wèn)題看法,用作學(xué)習(xí),回顧之用。
Service 前臺(tái)服務(wù)
請(qǐng)參看紫豪 http://www.lxweimin.com/p/5505390503fa