一、簡(jiǎn)介
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ù)在其托管進(jìn)程的主線程中運(yùn)行放仗,它既不創(chuàng)建自己的線程,也不在單獨(dú)的進(jìn)程中運(yùn)行(除非另行指定)撬碟。
二诞挨、AndroidManifest配置
使用Service必須在AndroidManifest中注冊(cè),如下:
<code><manifest ... >
...
<application ... >
<service android:name=".ExampleService" />
</application>
</manifest></code>
可以為service配置一些特定屬性呢蛤。
<code><service android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:icon="drawable resource"
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
</service></code>
android:name:屬性是唯一必需的屬性亭姥,用于指定服務(wù)的類名。
android:enabled:是否可被系統(tǒng)實(shí)例化顾稀,默認(rèn)true.
android:exported : 設(shè)為false則其它應(yīng)用(user ID不同)無(wú)法啟動(dòng)此服務(wù)达罗。默認(rèn)true。
android:permission:指定啟動(dòng)服務(wù)及其運(yùn)行所在進(jìn)程所需的權(quán)限静秆。
android:process:指定服務(wù)運(yùn)行進(jìn)程粮揉,默認(rèn)當(dāng)前應(yīng)用進(jìn)程。
注意:Android5.0以后禁止了隱式聲明Intent來(lái)啟動(dòng)Service抚笔》鋈希可以通過setPackage()解決或者把一個(gè)隱式Intent轉(zhuǎn)換成顯式Intent。
三殊橙、Service的生命周期
<code>public class ExampleService extends Service {
int mStartMode; // 聲明服務(wù)如果被系統(tǒng)回收之后的行為
IBinder mBinder; // 返回的用于和Service交互的Binder
boolean mAllowRebind; // 聲明onRebind是否被使用
@Override
public void onCreate() {
// 服務(wù)正被創(chuàng)建
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 由于調(diào)用了startService()辐宾,服務(wù)正在啟動(dòng)
// 返回值表明了服務(wù)如果被系統(tǒng)回收之后的行為
// 返回值START_NOT_STICKY
// 返回值START_STICKY
// 返回值START_REDELIVER_INTENT
return mStartMode;
}
@Override
public IBinder onBind(Intent intent) {
// 由于調(diào)用了bindService(),服務(wù)正在綁定
// 返回Binder
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// 服務(wù)的所有綁定都調(diào)用了unbindService()
// 返回值決定是否允許調(diào)用onRebind
return mAllowRebind;
}
@Override
public void onRebind(Intent intent) {
//調(diào)用了onUnbind并返回true,再次調(diào)用bindService()
}
@Override
public void onDestroy() {
//服務(wù)被銷毀
}
}</code>
對(duì)于長(zhǎng)時(shí)間運(yùn)行的服務(wù)膨蛮,系統(tǒng)會(huì)隨著時(shí)間的推移降低服務(wù)在后臺(tái)任務(wù)列表中的位置叠纹,而服務(wù)也將隨之變得非常容易被終止。當(dāng)內(nèi)存過低且必須回收系統(tǒng)資源以供具有用戶焦點(diǎn)的 Activity 使用時(shí)敞葛,Android 系統(tǒng)就會(huì)強(qiáng)制停止服務(wù)誉察。
如果將服務(wù)綁定到具有用戶焦點(diǎn)的 Activity,則它不太可能會(huì)終止惹谐;
如果將服務(wù)聲明為前臺(tái)服務(wù)持偏,則它幾乎永遠(yuǎn)不會(huì)終止。
如果服務(wù)是啟動(dòng)服務(wù)氨肌,則您必須將其設(shè)計(jì)為能夠妥善處理系統(tǒng)對(duì)它的重啟鸿秆。因?yàn)槿绻到y(tǒng)終止服務(wù),那么一旦資源變得再次可用怎囚,系統(tǒng)便會(huì)重啟服務(wù)卿叽。
四、IntentService
IntentService是Service的子類,創(chuàng)建了默認(rèn)線程附帽,使用者只需實(shí)現(xiàn)onHandleIntent()即可埠戳,IntentService具體執(zhí)行操作如下:
1.創(chuàng)建默認(rèn)的工作線程,用于在應(yīng)用的主線程外執(zhí)行傳遞給onStartCommand()的所有 Intent蕉扮。
2.創(chuàng)建工作隊(duì)列整胃,用于將一個(gè) Intent 逐一傳遞給onHandleIntent()實(shí)現(xiàn),這樣您就永遠(yuǎn)不必?fù)?dān)心多線程問題喳钟。
3.在處理完所有啟動(dòng)請(qǐng)求后停止服務(wù)屁使,因此您永遠(yuǎn)不必調(diào)用stopSelf()。
4.提供onBind()的默認(rèn)實(shí)現(xiàn)(返回 null)。
5.提供onStartCommand()的默認(rèn)實(shí)現(xiàn),可將Intent 依次發(fā)送到工作隊(duì)列和onHandleIntent()實(shí)現(xiàn)沟优。
代碼實(shí)現(xiàn):
<code>public class TestIntentService extends IntentService {
// 必須實(shí)現(xiàn)的構(gòu)造函數(shù)
//且需要調(diào)用父類的構(gòu)造函數(shù),傳入的參數(shù)就是創(chuàng)建的工作線程的名字
public TestIntentService() {
super("word_thread_name");
}
//唯一要實(shí)現(xiàn)的方法燃箭,方法返回則服務(wù)停止
@Override
protected void onHandleIntent(Intent intent) {
}</code>
五筛谚、startService
5.1簡(jiǎn)介
啟動(dòng)服務(wù):startService(Intent intent)
停止服務(wù):stopService(Intent intent);
如果組件通過調(diào)用startService()啟動(dòng)服務(wù)(這會(huì)導(dǎo)致對(duì)onStartCommand()
的調(diào)用),則服務(wù)將一直運(yùn)行,直到服務(wù)使用stopSelf()自行停止運(yùn)行,或由其他組件Intent會(huì)重新傳遞給Service范抓。
5.2 創(chuàng)建一個(gè)Service
<code>public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
HandlerThread thread = new HandlerThread("name");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
}
}</code>
每次startService都會(huì)回調(diào)onStartCommand方法。在這個(gè)方法中食铐,我們擁有在運(yùn)行Service時(shí)傳遞進(jìn)來(lái)的Intent匕垫,這樣就可以與Service交換一些信息。這個(gè)方法需要返回一個(gè)整型值虐呻。這個(gè)整型代表系統(tǒng)應(yīng)該怎么樣處理這個(gè)Service:
START_STICKY:使用這個(gè)返回值象泵,如果系統(tǒng)殺死我們的Service將會(huì)重新創(chuàng)建。但是斟叼,發(fā)送給Service的Intent不會(huì)再投遞偶惠。這樣Service是一直運(yùn)行的。
START_NOT_STICKY:如果系統(tǒng)殺死了Service犁柜,不會(huì)重新創(chuàng)建洲鸠,除非客戶端顯式地調(diào)用了onStart命令。
START_REDELIVER_INTENT:功能與START_STICKY類似馋缅。另外,在這種情況下
5.3 前臺(tái)運(yùn)行服務(wù)
前臺(tái)服務(wù)被認(rèn)為是用戶主動(dòng)意識(shí)到的一種服務(wù)绢淀,因此在內(nèi)存不足時(shí)萤悴,系統(tǒng)也不會(huì)考慮將其終止。
通過調(diào)用startForeground()設(shè)置服務(wù)為前臺(tái)服務(wù)皆的,代碼如下:
<code>Intent notificationIntent = new Intent(this, ServiceActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_launcher) .setWhen(System.currentTimeMillis())
.setContentText("content")
.setContentTitle("title")
.setContentIntent(pendingIntent)
.build();
startForeground(1111, notification);</code>
注意:前臺(tái)服務(wù)必須為狀態(tài)欄提供通知覆履,狀態(tài)欄位于“正在進(jìn)行”標(biāo)題下方,這意味著除非服務(wù)停止或從前臺(tái)刪除,否則不能清除通知硝全。
5.4 向用戶發(fā)送通知
服務(wù)可以發(fā)送Toast通知和狀態(tài)欄通知兩種栖雾。
六、bindService
6.1簡(jiǎn)介
綁定服務(wù):bindService(Intent intent,ServiceConnection conn,int flags)
解除綁定:unbindService(ServiceConnection conn)
如果組件是通過調(diào)用bindService()來(lái)創(chuàng)建服務(wù)伟众,則服務(wù)只會(huì)在該組件與其綁定時(shí)運(yùn)行析藕。一旦該服務(wù)與所有客戶端之間的綁定全部取消,系統(tǒng)便會(huì)銷毀它凳厢。
6.2綁定Service
要想綁定服務(wù)账胧,必須:
1.實(shí)現(xiàn) ServiceConnection。
重寫兩個(gè)回調(diào)方法:
onServiceConnected()
綁定時(shí)調(diào)用先紫,傳遞onBind()的返回值治泥。
onServiceDisconnected()
當(dāng)服務(wù)的連接意外中斷時(shí)(例如當(dāng)服務(wù)崩潰或被終止時(shí))調(diào)用該方法。注意:取消綁定時(shí)并不會(huì)調(diào)用遮精。
2.調(diào)用 bindService()
傳遞ServiceConnection對(duì)象
3.調(diào)用 unbindService()取消綁定居夹。
注意:當(dāng)Activity被銷毀時(shí),會(huì)取消與服務(wù)的綁定本冲。但您應(yīng)該始終在完成與服務(wù)的交互時(shí)或您的 Activity 暫停時(shí)取消綁定吮播,以便服務(wù)能夠在未被占用時(shí)關(guān)閉。
6.3擴(kuò)展Binder
如果服務(wù)是自有應(yīng)用專用眼俊,并且在相同的進(jìn)程中運(yùn)行意狠,則應(yīng)通過擴(kuò)展 Binder 類并從onBind() 返回它的一個(gè)實(shí)例來(lái)創(chuàng)建接口。
以下是具體的設(shè)置方法:
1 在您的服務(wù)中疮胖,創(chuàng)建一個(gè)可滿足下列任一要求的Binder實(shí)例:
包含可調(diào)用的公共方法
返回當(dāng)前Service實(shí)例环戈,Service中包含可調(diào)用的公共方法
或返回由服務(wù)承載的其他類的實(shí)例,其中包含可調(diào)用的公共方法
2.從onBind()回調(diào)方法返回此Binder實(shí)例澎灸。
3.從onServiceConnected()回調(diào)方法中接收Binder
注意:之所以要求服務(wù)和客戶端必須在同一應(yīng)用內(nèi)院塞,是為了便于客戶端轉(zhuǎn)換返回的對(duì)象和正確調(diào)用其 API。服務(wù)和客戶端還必須在同一進(jìn)程內(nèi)性昭,因?yàn)榇朔椒ú荒苋魏慰邕M(jìn)程執(zhí)行拦止。如果服務(wù)只是您的自有應(yīng)用的后臺(tái)工作線程,則優(yōu)先采用這種方法糜颠。 不以這種方式創(chuàng)建接口的唯一原因是汹族,您的服務(wù)被其他應(yīng)用或不同的進(jìn)程占用。
6.4使用Messenger
如需讓接口跨不同的進(jìn)程工作其兴,則可使用 Messenger 為服務(wù)創(chuàng)建接口顶瞒。服務(wù)可以這種方式定義對(duì)應(yīng)于不同類型 Message 對(duì)象的 Handler。此 Handler 是 Messenger 的基礎(chǔ)元旬,后者隨后可與客戶端分享一個(gè)IBinder榴徐,從而讓客戶端能利用 Message 對(duì)象向服務(wù)發(fā)送命令守问。此外,客戶端還可定義自有Messenger坑资,以便服務(wù)回傳消息耗帕。
以下是具體步驟:
1.服務(wù)實(shí)現(xiàn)一個(gè) Handler,由其接收來(lái)自客戶端的每個(gè)調(diào)用的回調(diào)
2.Handler 用于創(chuàng)建 Messenger 對(duì)象(對(duì) Handler 的引用)
3.Messenger 創(chuàng)建一個(gè) IBinder袱贮,服務(wù)通過 onBind() 使其返回客戶端
4.客戶端使用 IBinder 將 Messenger(引用服務(wù)的 Handler)實(shí)例化仿便,然后使用后者將 Message 對(duì)象發(fā)送給服務(wù)
5.服務(wù)在其 Handler 中(具體地講,是在 handleMessage() 方法中)接收每個(gè) Message
<code>public class MessageService extends Service {
private Messenger message = new Messenger(new MesHandler());
@Override
public IBinder onBind(Intent intent) {
return message.getBinder();
}
class MesHandler extends Handler{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
}</code>
這是執(zhí)行進(jìn)程間通信 (IPC) 的最簡(jiǎn)單方法字柠,因?yàn)?Messenger 會(huì)在單一線程中創(chuàng)建包含所有請(qǐng)求的隊(duì)列探越,這樣您就不必對(duì)服務(wù)進(jìn)行線程安全設(shè)計(jì)。
6.5使用AIDL
如需直接使用 AIDL窑业,您必須創(chuàng)建一個(gè)定義編程接口的 .aidl 文件钦幔。Android SDK 工具利用該文件生成一個(gè)實(shí)現(xiàn)接口并處理 IPC 的抽象類,您隨后可在服務(wù)內(nèi)對(duì)其進(jìn)行擴(kuò)展常柄。
之前采用 Messenger 的方法實(shí)際上是以 AIDL 作為其底層結(jié)構(gòu)鲤氢。Messenger 會(huì)在單一線程中創(chuàng)建包含所有客戶端請(qǐng)求的隊(duì)列,以便服務(wù)一次接收一個(gè)請(qǐng)求西潘。不過卷玉,如果您想讓服務(wù)同時(shí)處理多個(gè)請(qǐng)求,則可直接使用 AIDL喷市。 在此情況下相种,您的服務(wù)必須具備多線程處理能力,并采用線程安全式設(shè)計(jì)品姓。
6.6注意事項(xiàng)
1.應(yīng)該始終捕獲 DeadObjectException 異常寝并,它是在連接中斷時(shí)引發(fā)的,也是遠(yuǎn)程方法引發(fā)的唯一異常
2.對(duì)象是跨進(jìn)程計(jì)數(shù)的引用
3.通常應(yīng)配對(duì)綁定和取消綁定腹备。
例如:在 onStart() 綁定衬潦, onStop() 取消綁定≈菜郑或者在 onCreate() 綁定镀岛,onDestroy() 取消綁定。
4.通常情況下友驮,切勿在 Activity 的 onResume() 和 onPause() 期間綁定和取消綁定漂羊,因?yàn)槊恳淮紊芷谵D(zhuǎn)換都會(huì)發(fā)生這些回調(diào),您應(yīng)該使發(fā)生在這些轉(zhuǎn)換期間的處理保持在最低水平喊儡。
5.此外拨与,如果您的應(yīng)用內(nèi)的多個(gè) Activity 綁定到同一服務(wù),并且其中兩個(gè) Activity 之間發(fā)生了轉(zhuǎn)換艾猜,則如果當(dāng)前 Activity 在下一次綁定(恢復(fù)期間)之前取消綁定(暫停期間)买喧,系統(tǒng)可能會(huì)銷毀服務(wù)并重建服務(wù)。 (Activity文檔中介紹了這種有關(guān) Activity 如何協(xié)調(diào)其生命周期的 Activity 轉(zhuǎn)換匆赃。)