概述
- Service是一個(gè)可以在后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行操作而不使用用戶界面的應(yīng)用組件。
- 服務(wù)可由其他應(yīng)用組件啟動(dòng)盅藻,且即使用戶切換到其他應(yīng)用购桑,服務(wù)仍將在后臺(tái)繼續(xù)運(yùn)行。
- 組件可綁定到服務(wù)氏淑,以與之進(jìn)行交互勃蜘,甚至是執(zhí)行進(jìn)程間通信(IPC)。
- 服務(wù)可處理網(wǎng)路事務(wù)假残、播放音樂缭贡、執(zhí)行文件IO或與內(nèi)容提供程序交互。
Service類
要?jiǎng)?chuàng)建服務(wù)守问,必須創(chuàng)建Service的子類或使用它的一個(gè)現(xiàn)有子類匀归。
-
聲明服務(wù)
<manifest ... > ... <application ... > <service android:name="服務(wù)的包類名" android:exported="false" /> ... </application> </manifest>
-
重寫生命周期的回調(diào)方法
- onCreate()
- 何時(shí):首次創(chuàng)建服務(wù)時(shí)坑资。
- 注意:若服務(wù)已在運(yùn)行耗帕,則不會(huì)調(diào)用此方法。
- onDestroy()
- 何時(shí):當(dāng)服務(wù)不再使用且將被銷毀時(shí)袱贮。
- 作用:清理所有資源仿便,如線程、注冊(cè)的偵聽器、接收器等嗽仪。
- 注意:這是服務(wù)接收的最后一個(gè)調(diào)用荒勇。
- int onStartCommand(Intent intent, int flags, int startId)
- 何時(shí):當(dāng)另一個(gè)組件調(diào)用
startService()
請(qǐng)求啟動(dòng)服務(wù)時(shí)。 - 參數(shù):
- intent:
startService()
啟動(dòng)服務(wù)時(shí)傳入的Intent闻坚; - startId:唯一id標(biāo)識(shí)此次服務(wù)的啟動(dòng)請(qǐng)求沽翔。
- intent:
- 返回值:描述系統(tǒng)應(yīng)該如何在服務(wù)終止的情況下繼續(xù)運(yùn)行服務(wù)。
- 何時(shí):當(dāng)另一個(gè)組件調(diào)用
- IBinder onBind(Intent it)
- 何時(shí):當(dāng)另一個(gè)組件調(diào)用
bindService()
與服務(wù)綁定時(shí)窿凤。 - 返回值:供客戶端與服務(wù)進(jìn)行通信仅偎。
- 何時(shí):當(dāng)另一個(gè)組件調(diào)用
- onCreate()
-
服務(wù)的銷毀
- 調(diào)用
startService()
啟動(dòng)服務(wù),則服務(wù)將一直運(yùn)行雳殊,直到其自身使用stopSelf()
或由其他組件調(diào)用stopService()
來停止橘沥。 - 調(diào)用
bindService()
創(chuàng)建并綁定服務(wù),則服務(wù)只會(huì)在該組件與其綁定時(shí)運(yùn)行夯秃。一旦該服務(wù)與所有客戶端之間的綁定全部取消座咆,系統(tǒng)會(huì)銷毀它。 - 同時(shí)被啟動(dòng)和綁定的服務(wù)仓洼,要經(jīng)歷上面兩種才能被銷毀介陶。
- 僅當(dāng)內(nèi)存過低且必須回收系統(tǒng)資源以供具有用戶焦點(diǎn)的Activity使用時(shí),系統(tǒng)才會(huì)強(qiáng)制停止服務(wù)(前臺(tái)運(yùn)行的服務(wù)除外)色建。
- 調(diào)用
-
onStartCommand()
的返回值-
START_NOT_STICKY
- 默認(rèn)情況下斤蔓,系統(tǒng)不會(huì)重新創(chuàng)建服務(wù)。除非有將要傳遞來的Intent時(shí)镀岛,系統(tǒng)重新創(chuàng)建服務(wù)弦牡,并調(diào)用
onStartCommand()
,傳入此Intent漂羊。 - 這是最安全的選項(xiàng)驾锰,可以避免在不必要的時(shí)候運(yùn)行服務(wù)。
- 默認(rèn)情況下斤蔓,系統(tǒng)不會(huì)重新創(chuàng)建服務(wù)。除非有將要傳遞來的Intent時(shí)镀岛,系統(tǒng)重新創(chuàng)建服務(wù)弦牡,并調(diào)用
-
START_STICKY
- 系統(tǒng)重新創(chuàng)建服務(wù)走越,并調(diào)用
onStartCommand()
椭豫,默認(rèn)是傳入空Intent。除非存在將要傳遞來的Intent旨指,那么就傳遞這些Intent赏酥。 - 適合播放器一類的服務(wù)。獨(dú)立運(yùn)行谆构,但無需執(zhí)行命令裸扶,只等待任務(wù)。
- 系統(tǒng)重新創(chuàng)建服務(wù)走越,并調(diào)用
-
START_REDELIVER_INTENT
- 系統(tǒng)重新創(chuàng)建服務(wù)搬素,并調(diào)用
onStartCommand()
呵晨,傳入上次傳遞給服務(wù)執(zhí)行過的Intent魏保。 - 適合像下載一樣的服務(wù)。立即恢復(fù)摸屠,積極執(zhí)行谓罗。
- 系統(tǒng)重新創(chuàng)建服務(wù)搬素,并調(diào)用
-
啟動(dòng)服務(wù)
創(chuàng)建啟動(dòng)服務(wù)
1. 擴(kuò)展Service類
與APP同進(jìn)程的服務(wù)是運(yùn)行在主線程中,不可作耗時(shí)操作季二,但可以創(chuàng)建子線程來完成耗時(shí)操作檩咱。
創(chuàng)建Service的子類,重寫
onCreate()
胯舷、onStartCommand()
税手、onDestroy()
等方法。
2. 擴(kuò)展IntentService類
-
IntentService執(zhí)行以下操作:
- 創(chuàng)建工作子線程需纳,用于執(zhí)行傳遞給
onStartCommand()
的所有Intent芦倒; - 創(chuàng)建工作隊(duì)列,用于將Intent一個(gè)個(gè)傳遞給
onHandleIntent()
處理不翩; - 在處理完所有啟動(dòng)請(qǐng)求后停止服務(wù)兵扬。
- 提供
onBind()
的默認(rèn)實(shí)現(xiàn),返回null口蝠; - 提供
onStartCommand()
的默認(rèn)實(shí)現(xiàn)器钟,將Intent發(fā)送到工作隊(duì)列。
- 創(chuàng)建工作子線程需纳,用于執(zhí)行傳遞給
創(chuàng)建IntentService的子類妙蔗,只需要一個(gè)構(gòu)造函數(shù)和重寫
onHandleIntent()
即可傲霸。若重寫其他方法,要確保調(diào)用超類實(shí)現(xiàn)眉反,因?yàn)镮ntentService有自己的工作線程生命周期昙啄。
public class HelloIntentService extends IntentService {
/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
*/
public HelloIntentService() {
super("HelloIntentService");
}
/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
@Override
protected void onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent,flags,startId );
}
}
啟動(dòng)服務(wù)
-
startService(Intent it)
啟動(dòng)服務(wù)。
Intent intent = new Intent(this, HelloService.class);
startService(intent);
停止服務(wù)
- 服務(wù)必須通過調(diào)用
stopSelf()
自行停止運(yùn)行寸五,或者由另一個(gè)組件通過調(diào)用stopService()
來停止它梳凛。
綁定服務(wù)
創(chuàng)建Service的子類,必須重寫
onBind()
以返回IBinder梳杏,這個(gè)對(duì)象定義了組件與服務(wù)之間交互的編程接口韧拒。-
組件可通過調(diào)用
bindService(Intent service, ServiceConnection conn, int flags)
綁定到服務(wù)。- 參數(shù)service:能標(biāo)識(shí)要綁定服務(wù)十性;
- 參數(shù)conn:監(jiān)控服務(wù)的連接和斷開叛溢;
- 服務(wù)連接時(shí),會(huì)回調(diào)conn的
void onServiceConnected(ComponentName name, IBinder service)
劲适。 -
服務(wù)因crash或killed而斷開時(shí)楷掉,會(huì)回調(diào)conn的
void onServiceDisconnected(ComponentName name)
。
- 服務(wù)連接時(shí),會(huì)回調(diào)conn的
- 參數(shù)flags:綁定操作標(biāo)識(shí)减响【甘可選有
0, BIND_AUTO_CREATE, BIND_DEBUG_UNBIND, BIND_NOT_FOREGROUND,BIND_ABOVE_CLIENT, BIND_ALLOW_OOM_MANAGEMENT, BIND_WAIVE_PRIORITY
。
組件可通過調(diào)用
unbindService(ServiceConnection conn)
解綁支示。多個(gè)應(yīng)用組件可以同時(shí)綁定同一個(gè)服務(wù)刊橘。不過,只有在第一個(gè)組件綁定時(shí)颂鸿,系統(tǒng)才會(huì)調(diào)用服務(wù)的
onBind()
方法來創(chuàng)建IBinder促绵。當(dāng)最后一個(gè)客戶端取消與服務(wù)的綁定時(shí),系統(tǒng)會(huì)將服務(wù)銷毀(除非
startService()
也啟動(dòng)了該服務(wù))嘴纺。
IBinder接口實(shí)現(xiàn)
- 綁定服務(wù)提供給客戶端組件败晴,用來組件與服務(wù)進(jìn)行交互的編程接口。
1.擴(kuò)展IBinder類
若你的服務(wù)僅供本地APP使用栽渴,不需要跨進(jìn)程尖坤,則可實(shí)現(xiàn)自有Binder類,讓你的客戶端通過該類直接訪問服務(wù)中的公共方法闲擦。
這個(gè)實(shí)現(xiàn)方案只有在客戶端和服務(wù)位于同一個(gè)APP同一個(gè)進(jìn)程內(nèi)才有效慢味。
-
設(shè)置方法
- 在服務(wù)類中,創(chuàng)建Binder實(shí)例墅冷,要滿足以下任一要求:
- 包含客戶端可調(diào)用的公共方法纯路;
- 返回當(dāng)前服務(wù)實(shí)例,該服務(wù)要包含客戶端可調(diào)用的公共方法寞忿;
- 返回由服務(wù)承載的其他類的實(shí)例驰唬,該實(shí)例要包含客戶端可調(diào)用的公共方法。
- 在服務(wù)的
onBind()
回調(diào)方法中返回此Binder實(shí)例腔彰。 - 在客戶端中叫编,從
onServiceConnected()
回調(diào)方法中接收Binder,并使用其提供的公共方法操作服務(wù)霹抛。
- 在服務(wù)類中,創(chuàng)建Binder實(shí)例墅冷,要滿足以下任一要求:
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);
}
}
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Defines callbacks for service binding, passed to bindService() */
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;
}
};
}
2.使用Messenger
- 如需讓服務(wù)與遠(yuǎn)程進(jìn)程通信宵溅,則可使用Messenger。
- 服務(wù)類中實(shí)現(xiàn)一個(gè)Handler上炎,由其接收來自客戶端的每個(gè)調(diào)用的回調(diào)恃逻;
- 創(chuàng)建Messenger對(duì)象時(shí)需傳入Handler;
- 在
onBind()
時(shí)返回Messenger對(duì)象.getBinder()
給客戶端藕施; - 客戶端在
onServiceConnected()
中接收到IBinder寇损,并將其強(qiáng)制類型轉(zhuǎn)換為Messenger對(duì)象。調(diào)用Messenger的send(Message msg)
來給服務(wù)發(fā)送消息裳食; - 服務(wù)類中的Handler的
handleMessage()
接收客戶端發(fā)來的消息矛市。
public class MessengerService extends Service {
/** Command to the service to display a message */
static final int MSG_SAY_HELLO = 1;
/**
* Handler of incoming messages from clients.
*/
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
public class ActivityMessenger extends Activity {
/** Messenger for communicating with the service. */
Messenger mService = null;
/** Flag indicating whether we have called bind on the service. */
boolean mBound;
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mBound = false;
}
};
public void sayHello(View v) {
if (!mBound) return;
// Create and send a message to the service, using a supported 'what' value
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
3.使用AIDL
- 參考AILD筆記
綁定與解綁服務(wù)
-
流程簡(jiǎn)述
- 客戶端實(shí)現(xiàn)ServiceConnection
- 重寫
onServiceConnected()
- 重寫
onServiceDisconnected()
- 客戶端調(diào)用
bindService()
綁定服務(wù)
- 重寫
- 與服務(wù)連接時(shí),系統(tǒng)會(huì)回調(diào)
onServiceConnected
诲祸,要保存IBinder對(duì)象浊吏,并使用其調(diào)用服務(wù)而昨。 - 客戶端調(diào)用
unbindService()
解綁服務(wù)。注意找田,此時(shí)不會(huì)回調(diào)onServiceDisconnected()
歌憨,這個(gè)方法只會(huì)在服務(wù)crash或killed才會(huì)被回調(diào)。
- 客戶端實(shí)現(xiàn)ServiceConnection
-
何時(shí)綁定與何時(shí)解綁
- 若只需要在Activity可見時(shí)與服務(wù)交互墩衙,則應(yīng)在
onStart()
期間綁定务嫡,在onStop()
期間解綁。 - 若希望Activity在后臺(tái)停止運(yùn)行時(shí)仍可接收響應(yīng)漆改,則在
onCreate()
期間綁定心铃,在onDestroy()
期間解綁。 - 切勿在
onResume()
期間綁定和onPause()
期間解綁挫剑,這是因?yàn)槊恳淮紊芷谵D(zhuǎn)換都會(huì)發(fā)生這些回調(diào)去扣,頻率過高。
- 若只需要在Activity可見時(shí)與服務(wù)交互墩衙,則應(yīng)在
綁定服務(wù)的生命周期
- 綁定服務(wù)的回調(diào)方法解析
- IBinder onBind(Intent intent);
- 參數(shù)intent:來自客戶端組件的
bindService()
樊破。 - 返回值:提供給客戶端訪問服務(wù)的公共方法厅篓。
- 何時(shí)被系統(tǒng)調(diào)用:服務(wù)被首次綁定,且
onUnbind()
返回false捶码。
- 參數(shù)intent:來自客戶端組件的
- boolean onUnbind(Intent intent);
- 參數(shù)intent:來自客戶端組件的
bindService()
羽氮。 - 返回值:返回true表明當(dāng)之后被新客戶端綁定時(shí),不調(diào)用
onBind()
惫恼,而是調(diào)用onRebind()
档押。 - 何時(shí)被系統(tǒng)調(diào)用:當(dāng)所有客戶端都解綁時(shí)。
- 參數(shù)intent:來自客戶端組件的
- void onRebind(Intent intent);
- 參數(shù)intent:來自客戶端組件的
bindService()
祈纯。 - 何時(shí)被系統(tǒng)調(diào)用:經(jīng)歷過所有客戶端解綁令宿,且
onUnbind()
返回true之后,有新的客戶端綁定腕窥。
- 參數(shù)intent:來自客戶端組件的
- IBinder onBind(Intent intent);
前臺(tái)服務(wù)
服務(wù)一般都是運(yùn)行在后臺(tái)粒没,系統(tǒng)優(yōu)先級(jí)比較低,當(dāng)系統(tǒng)內(nèi)存不足時(shí)簇爆,很有可能被回收掉癞松。而前臺(tái)服務(wù)被認(rèn)為是用戶主動(dòng)意識(shí)到的一種服務(wù),因此即使內(nèi)存不足入蛆,系統(tǒng)也不會(huì)考慮將其終止响蓉。
前臺(tái)服務(wù)必須為狀態(tài)欄提供通知,也就是說除非服務(wù)停止或從前臺(tái)刪除哨毁,否則不能清除通知枫甲。
-
Service類的
void startForeground(int id, Notification notification)
可讓服務(wù)運(yùn)行于前臺(tái)。- 參數(shù)id:通知的唯一標(biāo)識(shí),不可為0想幻;
- 參數(shù)notification:在狀態(tài)欄上顯示粱栖,表明這是前臺(tái)服務(wù)的通知。
Service類的
void stopForeground(boolean removeNotification)
可停止前臺(tái)服務(wù)脏毯,布爾值參數(shù)指示是否刪除狀態(tài)欄的通知闹究。注意此方法不會(huì)停止普通服務(wù),只是針對(duì)前臺(tái)服務(wù)抄沮。
服務(wù)的生命周期
- 啟動(dòng)服務(wù)
- 一個(gè)組件調(diào)用
startService()
啟動(dòng)服務(wù)跋核,服務(wù)不存在則會(huì)創(chuàng)建且onCreate()
被系統(tǒng)調(diào)用岖瑰; -
onStartCommand()
被系統(tǒng)調(diào)用叛买; - 這種服務(wù)可無限地運(yùn)行下去,必須自己調(diào)用
stopSelf()
或調(diào)用stopService()
來停止它蹋订,onDestroy()
被系統(tǒng)調(diào)用率挣。
- 一個(gè)組件調(diào)用
- 綁定服務(wù)
- 一個(gè)組件調(diào)用
bindService()
綁定服務(wù),服務(wù)不存在則會(huì)創(chuàng)建且onCreate()
被系統(tǒng)調(diào)用露戒; -
onBind()
被系統(tǒng)調(diào)用椒功,并返回IBinder,提供給組件與服務(wù)進(jìn)行通信智什; - 組件調(diào)用
onbindService()
來解綁动漾。多個(gè)組件可綁定到同一服務(wù),當(dāng)所有解綁后荠锭,其onUnbind()
被調(diào)用旱眯,之后系統(tǒng)會(huì)銷毀它且調(diào)用其onDestroy()
。
- 一個(gè)組件調(diào)用
- 混合服務(wù)
- 以上兩條路徑并非完全獨(dú)立证九。服務(wù)可被啟動(dòng)和被綁定删豺,這種混合服務(wù)只有在所有組件解綁,且自身調(diào)用
stopSelf()
或調(diào)用stopService()
才會(huì)停止運(yùn)行愧怜。
- 以上兩條路徑并非完全獨(dú)立证九。服務(wù)可被啟動(dòng)和被綁定删豺,這種混合服務(wù)只有在所有組件解綁,且自身調(diào)用