Service系列一共2篇,主要介紹Service相關的使用,以及使用Service實現IPC通訊。本文的重點是介紹Service相關的使用,通過Service 實現IPC通訊放在下一篇講解。
What is a Service
根據官方的介紹:
- Service既不是一個執行緒,Service通常執行在當成宿主程式的主執行緒中,所以在Service中進行一些耗時操作就需要在Service內部開啟執行緒去操作,否則會引發ANR異常。
- 也不是一個單獨的程式。除非在清單檔案中宣告時指定程式名,否則Service所在程式就是application所在程式。
Service存在的目的有2個:
- 告訴系統,當前程式需要在後臺做一些處理。這意味著,Service可以不需要UI就在後臺執行,不用管開啟它的頁面是否被銷燬,只要程式還在就可以在後臺執行。可以通過startService()方式呼叫,這裡需要注意,除非Service手動呼叫stopService()或者Service內部主動呼叫了stopSelf(),否則Service一直執行。
- 程式通過Service對外開放某些操作。通過bindService()方式與Service呼叫,長期連線和互動,Service生命週期和其繫結的元件相關。
Service Lifecycle
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return startCommandReturnId;
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
複製程式碼
要解釋這個首先要知道Service的實現,需要實現抽象方法onBind,以及重寫onStartCommand,這2個方法會在下文介紹到。
通過上面的介紹可以知道,Service有3種啟動方式:
- startService()
- bindService()
- 同時呼叫
這幾種方式啟動的Service生命週期略微不同。
startService方式
startService()只要一個Intent引數,指定要開啟的Service即可
Intent intent = new Intent(MainActivity.this, MyService.class);
複製程式碼
-
當呼叫Service的startService()後,
- Service首次啟動,則先呼叫onCreate(),在呼叫onStartCommand()
- Service已經啟動,則直接呼叫onStartCommand()
-
當呼叫stopSelf()或者stopService()後,會執行onDestroy(),代表Service生命週期結束。
-
startService方式啟動Service不會呼叫到onBind()。
startService可以多次呼叫,每次呼叫都會執行onStartCommand()。
不管呼叫多少次startService,只需要呼叫一次stopService就結束。
如果startService後沒有呼叫stopSelf或者stopService,則Service一直存活並執行在後臺。 -
onStartCommand的返回值一共有3種
- START_STICKY = 1:service所在程式被kill之後,系統會保留service狀態為開始狀態。系統嘗試重啟service,當服務被再次啟動,傳遞過來的intent可能為null,需要注意。
- START_NOT_STICKY = 2:service所在程式被kill之後,系統不再重啟服務
- START_REDELIVER_INTENT = 3:系統自動重啟service,並傳遞之前的intent
預設返回START_STICKY;
bindService方式
通過bindService繫結Service相對startService方式要複雜一點。
由於bindService是非同步執行的,所以需要額外構建一個ServiceConnection物件用與接收bindService的狀態,同時還要指定bindService的型別。
//1. 定義用於通訊的物件,在Service的onBind()中返回的物件。
public class MyBind extends Binder {
public int mProcessId;
}
//2. 定義用於接收狀體的ServiceConnection
mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//和服務繫結成功後,服務會回撥該方法
//服務異常中斷後重啟,也會重新呼叫改方法
MyService.MyBind myBinder = (MyService.MyBind) service;
}
@Override
public void onNullBinding(ComponentName name) {
//Service的onBind()返回null時將會呼叫這個方法,並不會呼叫onServiceConnected()
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 當服務異常終止時會呼叫。
// 注意,unbindService時不會呼叫
}
};
//3. 在需要的地方繫結到Service
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
複製程式碼
bindService()也可以呼叫多次,與startService()不同,當發起物件與Service已經成功繫結後,不會多次返回ServiceConnection中的回撥方法。
通過bindService方式與Service進行繫結後,當沒有物件與Service繫結後,Service生命週期結束,這個過程包括繫結物件被銷燬,或者主動掉呼叫unbindService()
startService和bindService同時開啟
當同時呼叫startService和bindService後,需要分別呼叫stopService和unbindService,Service才會走onDestroy()
一個Service必須要在既沒有和任何Activity關聯又處理停止狀態的時候才會被銷燬。
IntentService
通過上面的介紹我們知道,通過StartService形式開啟Service時,如果不主動呼叫stopService,Service將在後臺一直執行。同時如果我們在Service中執行耗時操作還是引起ANR異常,為了解決這2個問題,IntentService出現了。
當我們需要執行某些一次性、非同步的操作時,IntentService能很好的滿足這個場景。
IntentService相比於普通的Service,在使用時將不再需要實現onStartCommand(),同時需要實現onHandleIntent()。
真正需要我們處理的邏輯就在onHandleIntent()實現,IntentService會內部自動呼叫stopSelf()關閉自己。
至於防止ANR異常,具體的實現方式其實還是挺簡單,就是在內部新建了子執行緒,並在子執行緒中內部的Looper來分發事件,具體程式碼就不貼了。