Service介紹
Service(服務(wù))是一個(gè)可以再后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行操作而沒(méi)有用戶界面的應(yīng)用組件。服務(wù)可用其他應(yīng)用組件啟動(dòng),服務(wù)一旦被啟動(dòng)將在后臺(tái)一直運(yùn)行,即使啟動(dòng)服務(wù)的組件銷(xiāo)毀也不會(huì)影響它。
比如:服務(wù)可以處理網(wǎng)絡(luò)請(qǐng)求,播放音樂(lè),執(zhí)行文件I/O等,一切都可以在后臺(tái)運(yùn)行。
服務(wù)的兩種形式:
- 啟動(dòng)狀態(tài)
應(yīng)用組件調(diào)用startService()啟動(dòng)服務(wù),服務(wù)就處于‘啟動(dòng)’狀態(tài),就可以在后臺(tái)一直運(yùn)行,除非手動(dòng)停止服務(wù) - 綁定狀態(tài)
當(dāng)應(yīng)用組件通過(guò)調(diào)用bindService()綁定服務(wù)時(shí),服務(wù)處于‘綁定’狀態(tài)。綁定服務(wù)提供一個(gè)客戶端-服務(wù)的接口,運(yùn)行組件和服務(wù)進(jìn)行交互。
Service使用
定義服務(wù)
public class MyTestService extends Service {
public static final String TAG = "MyTestService";
public MyTestService() {
}
/**
* 首次創(chuàng)建服務(wù)時(shí),系統(tǒng)會(huì)執(zhí)行一次onCreate;
* 如果服務(wù)已經(jīng)啟動(dòng),不會(huì)再調(diào)用
*/
@Override
public void onCreate() {
Log.d(TAG, "onCreate");
super.onCreate();
}
/**
* 每次調(diào)用startService()方法啟動(dòng)服務(wù)都會(huì)被調(diào)用
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
/**
* 綁定服務(wù)(bindService)時(shí)才會(huì)調(diào)用
* 把Binder返回客戶端,對(duì)應(yīng)onServiceConnected的IBinder
* @param intent
* @return
*/
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return new MyBinder();
}
/**
* 解除綁定時(shí)回調(diào)
* @param intent
* @return
*/
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind");
return super.onUnbind(intent);
}
/**
* 服務(wù)銷(xiāo)毀時(shí)回調(diào)
*/
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
/**
* 服務(wù)內(nèi)定義的方法,提供外部調(diào)用
*/
public void testMethod(){
Log.d(TAG, "testMethod");
}
/**
* 定義Binder對(duì)象,返回客戶端使用,內(nèi)部定義了一個(gè)返回服務(wù)實(shí)例的方法
*/
class MyBinder extends Binder{
/**
* 返回本服務(wù)實(shí)例(給客戶端調(diào)用)
* @return
*/
public MyTestService getServer(){
// 返回服務(wù)對(duì)象,這樣客戶端就可以調(diào)用服務(wù)的公共方法了
return MyTestService.this;
}
}
}
清單定義(應(yīng)用組件都需要在清單中定義Activity,Service, Receiver, Provider):
<service android:name=".MyTestService" android:enabled="true" android:exported="true"/>
啟動(dòng)服務(wù)/停止服務(wù):
startService(new Intent(this, MyTestService.class));
stopService(new Intent(this, MyTestService.class));
服務(wù)生命周期:
onCreate() -> onStartCommand() -- 服務(wù)啟動(dòng) -- onDestory()
應(yīng)用設(shè)置那邊可以看到運(yùn)行的服務(wù):

image.png
綁定服務(wù)和解除綁定:
Intent intent = new Intent(this, MyTestService.class);
bindService(intent, cnn, BIND_AUTO_CREATE);
/**
* ServiceConnection代表與服務(wù)的連接,
* onServiceConnected代表連接一個(gè)服務(wù)成功后被調(diào)用,IBinder返回服務(wù)的onBinder的對(duì)象
* onServiceDisconnected是在服務(wù)崩潰或被殺死導(dǎo)致的連接中斷時(shí)被調(diào)用,一般不會(huì)被調(diào)用
*/
ServiceConnection cnn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.d("###", "onServiceConnected");
// 獲取Binder對(duì)象
MyTestService.MyBinder binder = (MyTestService.MyBinder)iBinder;
// 調(diào)用Binder的方法,返回服務(wù)實(shí)例
myTestService = binder.getServer();
// 調(diào)用服務(wù)的方法
myTestService.testMethod();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.d("###", "onServiceDisconnected");
}
};
unbindService(cnn); // 解除綁定
生命周期:
onCreate() -> onBind() -> 服務(wù)綁定 -> onUnbind() -> onDestory()
使用綁定服務(wù),都是為了調(diào)用服務(wù)的方法,因此在不需要的時(shí)候及時(shí)解綁防止內(nèi)存泄漏。
附上一張綁定邏輯圖:

image.png
注意:
- 這種綁定服務(wù)的方式,需要和服務(wù)在同一個(gè)進(jìn)程中,否則會(huì)調(diào)用失敗。
我們把服務(wù)設(shè)置一個(gè)進(jìn)程名::mytestservice表示包名:mytestservice
<service
android:name=".MyTestService"
android:enabled="true"
android:exported="true"
android:process=":mytestservice"/>
startService啟動(dòng)服務(wù)的方式還是可以的,日志都打在服務(wù)的進(jìn)程上了。

image.png
而使用綁定的方式出現(xiàn)異常:

image.png
此時(shí)跨進(jìn)程的方式需要使用Messenger和AIDL.
- 服務(wù)的執(zhí)行代碼是在主線程上的,因此不能處理太耗時(shí)的操作。如果需要耗時(shí)操作,還是需要?jiǎng)?chuàng)建線程,或者可以使用IntentService.