startService與bindService的區別
Android執行Service有兩種方法,一種是startService,一種是bindService。下面讓我們一起來聊一聊這兩種執行Service方法的區別。
1、生命週期上的區別
執行startService時,Service會經歷onCreate->onStartCommand。當執行stopService時,直接呼叫onDestroy方法。呼叫者如果沒有stopService,Service會一直在後臺執行,下次呼叫者再起來仍然可以stopService。
執行bindService時,Service會經歷onCreate->onBind。這個時候呼叫者和Service繫結在一起。呼叫者呼叫unbindService方法或者呼叫者Context不存在了(如Activity被finish了),Service就會呼叫onUnbind->onDestroy。這裡所謂的繫結在一起就是說兩者共存亡了。
多次呼叫startService,該Service只能被建立一次,即該Service的onCreate方法只會被呼叫一次。但是每次呼叫startService,onStartCommand方法都會被呼叫。Service的onStart方法在API 5時被廢棄,替代它的是onStartCommand方法。
第一次執行bindService時,onCreate和onBind方法會被呼叫,但是多次執行bindService時,onCreate和onBind方法並不會被多次呼叫,即並不會多次建立服務和繫結服務。
2、呼叫者如何獲取繫結後的Service的方法
onBind回撥方法將返回給客戶端一個IBinder介面例項,IBinder允許客戶端回撥服務的方法,比如得到Service執行的狀態或其他操作。我們需要IBinder物件返回具體的Service物件才能操作,所以說具體的Service物件必須首先實現Binder物件。
3、既使用startService又使用bindService的情況
如果一個Service又被啟動又被繫結,則該Service會一直在後臺執行。首先不管如何呼叫,onCreate始終只會呼叫一次。對應startService呼叫多少次,Service的onStart方法便會呼叫多少次。Service的終止,需要unbindService和stopService同時呼叫才行。不管startService與bindService的呼叫順序,如果先呼叫unbindService,此時服務不會自動終止,再呼叫stopService之後,服務才會終止;如果先呼叫stopService,此時服務也不會終止,而再呼叫unbindService或者之前呼叫bindService的Context不存在了(如Activity被finish的時候)之後,服務才會自動停止。
那麼,什麼情況下既使用startService,又使用bindService呢?
如果你只是想要啟動一個後臺服務長期進行某項任務,那麼使用startService便可以了。如果你還想要與正在執行的Service取得聯絡,那麼有兩種方法:一種是使用broadcast,另一種是使用bindService。前者的缺點是如果交流較為頻繁,容易造成效能上的問題,而後者則沒有這些問題。因此,這種情況就需要startService和bindService一起使用了。
另外,如果你的服務只是公開一個遠端介面,供連線上的客戶端(Android的Service是C/S架構)遠端呼叫執行方法,這個時候你可以不讓服務一開始就執行,而只是bindService,這樣在第一次bindService的時候才會建立服務的例項執行它,這會節約很多系統資源,特別是如果你的服務是遠端服務,那麼效果會越明顯(當然在Servcie建立的是偶會花去一定時間,這點需要注意)。
4、本地服務與遠端服務
本地服務依附在主程序上,在一定程度上節約了資源。本地服務因為是在同一程序,因此不需要IPC,也不需要AIDL。相應bindService會方便很多。缺點是主程序被kill後,服務變會終止。
遠端服務是獨立的程序,對應程序名格式為所在包名加上你指定的android:process字串。由於是獨立的程序,因此在Activity所在程序被kill的是偶,該服務依然在執行。缺點是該服務是獨立的程序,會佔用一定資源,並且使用AIDL進行IPC稍微麻煩一點。
對於startService來說,不管是本地服務還是遠端服務,我們需要做的工作都一樣簡單。
5、程式碼例項
startService啟動服務
public class LocalService1 extends Service {
/**
* onBind 是 Service 的虛方法,因此我們不得不實現它。
* 返回 null,表示客服端不能建立到此服務的連線。
*/
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onStartCommand(Intent intent, int startId, int flags) {
super.onStartCommand(intent, startId, flags);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
bindService繫結服務
public class LocalService extends Service {
/**
* 在 Local Service 中我們直接繼承 Binder 而不是 IBinder,因為 Binder 實現了 IBinder 介面,這樣我們可以** 少做很多工作。
*/
public class SimpleBinder extends Binder{
/**
* 獲取 Service 例項
* @return
*/
public LocalService getService(){
return LocalService.this;
}
public int add(int a, int b){
return a + b;
}
}
public SimpleBinder sBinder;
@Override
public void onCreate() {
super.onCreate();
// 建立 SimpleBinder
sBinder = new SimpleBinder();
}
@Override
public IBinder onBind(Intent intent) {
// 返回 SimpleBinder 物件
return sBinder;
}
}
上面的程式碼關鍵之處,在於 onBind(Intent) 這個方法 返回了一個實現了 IBinder 介面的物件,這個物件將用於繫結Service 的 Activity 與 Local Service 通訊。
下面是 Activity 中的程式碼:
public class Main extends Activity {
private final static String TAG = "SERVICE_TEST";
private ServiceConnection sc;
private boolean isBind;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
sc = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LocalService.SimpleBinder sBinder = (LocalService.SimpleBinder)service;
Log.v(TAG, "3 + 5 = " + sBinder.add(3, 5));
Log.v(TAG, sBinder.getService().toString());
}
};
findViewById(R.id.btnBind).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
bindService(new Intent(Main.this, LocalService.class), sc, Context.BIND_AUTO_CREATE);
isBind = true;
}
});
findViewById(R.id.btnUnbind).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(isBind){
unbindService(sc);
isBind = false;
}
}
});
}
}
6、在AndroidManifest.xml裡Service元素常見選項
android:name ------------- 服務類名
android:label -------------- 服務的名字,如果此項不設定,那麼預設顯示的服務名則為類名
android:icon -------------- 服務的圖示
android:permission ------- 申明此服務的許可權,這意味著只有提供了該許可權的應用才能控制或連線此服務
android:process ---------- 表示該服務是否執行在另外一個程序,如果設定了此項,那麼將會在包名後面加上這段字串表示另一程序的名字
android:enabled ---------- 表示是否能被系統例項化,為true表示可以,為false表示不可以,預設為true
android:exported --------- 表示該服務是否能夠被其他應用程式所控制或連線,不設定預設此項為 false