簡介
Service作爲Android的四大組件之一,它的重要性不言而喻,之前雖說看過一些介紹但是一直沒有用過,最近需要用到的時候發現無從下手,便閱讀了官方的有關Service的Guide,這裏總結一下。
Service作用
官方介紹如下
A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use.
Service主要用於在後臺執行長期任務或者耗時操作,在需要的時候甚至可以在應用退出的時候保持運行狀態。
Service與Thread
雖說Service可以在後臺執行任務,但是實際上一個Service是運行在主線程的,如果有耗時操作我們必須在Service中自己開啓一個Thread避免ANR。那就會有這麼一個問題,我們爲什麼不用Thread呢?主要的原因就是Thread的可控性不好,假設我們在一個Activity中啓動了一個Thread,一旦這個Activity結束了,那麼其他的Activity就沒有辦法拿到這個Thread的引用,更別談控制了。可是Service不一樣,一個Service整個程序只會創建一個實例,而且任何Activity都可以控制,那麼Service裏的Thread就可以由所有Activity控制了。而且Service作爲四大組件之一,有較高級別,在後臺運行不容易被系統殺掉。
Service分類
Service分爲兩類
- Started Service:不和其他組件通信
Bound Service:可以和其他組件通信
無論使用哪一種Service都必須重寫onBind()方法,如果使用Started Service返回null就可以了。
使用Started Service
一般需要再重寫兩個方法
- onCreate():啓動Service的時候並不存在該Service實例,就會調用該方法。
- onStartCommand(Intent intent, int flags, int startId):每次通過startService(Intent intent)啓動的時候就會掉用該方法,一般在這裏開啓新線程。
onStartCommand(Intent intent, int flags, int startId)方法返回int類型的值,代表Service被kill後的行爲,有以下三種:
- START_NOT_STICKY:表示不重新創建
- START_STICKY:表示重新創建,調用onStartCommand傳入null
- START_REDELIVER_INTENT:表示重建,調用onStartCommand傳入上一個Intent
爲了節省資源和電量,我們在任務結束後必須關閉Service,想要關閉Service可以通過本身調用stopSelf()或者其他組件調用stopService(),但是如果我們的Service處理多個onStartCommand請求的時候,我們在請求結束後掉用stopSelf()可能會打斷已經收到的新的請求,最好的情況就是我們本身就是最後一個請求,stopSelt(int)的一個參數的重載可以解決這個方法,傳入的id就是onStartCommand傳遞進來的id,代表當前任務的id,它會把傳入的id和最後一個id比較,如果一樣的話就代表本身是最後一個任務,就會stop掉,否則不會執行stop。
使用Bound Service
主要和Started Service的區別就是可以和其他組件通信,通過Binder。
創建時必須定義接口描述用戶如何與Server交流,接口必須繼承Binder。使用bindService()創建,必須提供一個ServiceConnection的實現,,bindService()是一個異步方法,立馬回返回。當創建完後會調用ServiceConnection的onServiceConnected,並傳遞binder通信。onBind方法只在第一個用戶連接調用,後來都返回同一個binder(因爲只會有一個Service),代碼如下
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
bind service的代碼如下
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
bindService(intent, mConnection, 0);
可以看出我們在Service中自定義了binder繼承自Binder,並聲明瞭一個方法,然後在onBind()中返回一個實例。我們會在onServiceConnected方法中得到這個binder,然後我們調用裏的方法得到Service的實例,這樣就可以掉用裏面方法了,也就完成了通信。bindServicer第三個參數是剛開始的選擇,如果是BIND_AUTO_CREATE表示如果沒啓動就新建
注意事項
onServiceDisconnected方法不是unbind的時候調用的,實在被kill等意外情況調用的