Android四大組件之Service

1、什么是service

一個(gè)可以在后臺(tái)執(zhí)行長(zhǎng)時(shí)間操作而不需要用戶界面的應(yīng)用組件。

需要注意的是:

- 服務(wù)并不是運(yùn)行在一個(gè)獨(dú)立的進(jìn)程中,而是依賴于創(chuàng)建服務(wù)時(shí)所在的應(yīng)用程序進(jìn)程。也就是運(yùn)行在主線程中。

- 服務(wù)并不會(huì)自動(dòng)開啟線程,所有的代碼都默認(rèn)運(yùn)行在主線程中。也就是說(shuō)我們需要在服務(wù)的內(nèi)部手動(dòng)創(chuàng)建子線程,并在這里執(zhí)行具體的任務(wù),否則就可能出現(xiàn)主線程被阻塞的情況。

2、如何創(chuàng)建service

- 定義一個(gè)類繼承Sevice,或者其子類IntentService(區(qū)別在后面講到),重寫里面一寫關(guān)鍵的回調(diào)方法。

- 并在清單文件中申明,并根據(jù)需要配置一些其他屬性。

~~~

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" >

~~~

android:enabled : 如果為true,則這個(gè)service可以被系統(tǒng)實(shí)例化,如果為false,則不行。默認(rèn)為true

android:exported : 如果為true,則其他應(yīng)用的組件也可以調(diào)用這個(gè)service并且可以與它進(jìn)行互動(dòng),如果為false,則只有與service同一個(gè)應(yīng)用或者相同user ID的應(yīng)用可以開啟或綁定此service。它的默認(rèn)值取決于service是否有intent filters。如果一個(gè)filter都沒(méi)有,就意味著只有指定了service的準(zhǔn)確的類名才能調(diào)用,也就是說(shuō)這個(gè)service只能應(yīng)用內(nèi)部使用——其他的應(yīng)用不知道它的類名。這種情況下exported的默認(rèn)值就為false。反之,只要有了一個(gè)filter,就意味著service是考慮到外界使用的情況的,這時(shí)exported的默認(rèn)值就為true

android:icon : 一個(gè)象征著這個(gè)service的icon

android:isolatedProcess : 如果設(shè)置為true,這個(gè)service將運(yùn)行在一個(gè)從系統(tǒng)中其他部分分離出來(lái)的特殊進(jìn)程中,我們只能通過(guò)Service API來(lái)與它進(jìn)行交流。默認(rèn)為false。

android:label : 顯示給用戶的這個(gè)service的名字。如果不設(shè)置,將會(huì)默認(rèn)使用的label屬性。

android:name : 這個(gè)service的路徑名,例如“com.lypeer.demo.MyService”。這個(gè)屬性是唯一一個(gè)必須填的屬性。

android:permission : 其他組件必須具有所填的權(quán)限才能啟動(dòng)這個(gè)service。

android:process : service運(yùn)行的進(jìn)程的name。默認(rèn)啟動(dòng)的service是運(yùn)行在主進(jìn)程中的。

3、如何啟動(dòng)service

startService()方式

組件如activity通過(guò)調(diào)用startStartService()方法,就可以啟動(dòng)一個(gè)特定的service,在方法中傳遞一個(gè)intent參數(shù),通關(guān)intent參數(shù)獲取數(shù)據(jù)。一旦啟動(dòng)后,service就會(huì)獨(dú)立運(yùn)行在后臺(tái),即使調(diào)用的組件以及銷毀,service還可以繼續(xù)在后臺(tái)運(yùn)行。當(dāng)操作完成后service自行調(diào)用stopService()或者有組件調(diào)用針對(duì)它的stopService()來(lái)結(jié)束運(yùn)行。應(yīng)用被強(qiáng)制清理,service也會(huì)被殺死。

bindService()方式

比startService()方式復(fù)雜,同時(shí)使用這種方式啟動(dòng)的service也能完成更多的事情,比如其他組件可向其發(fā)送請(qǐng)求,接受來(lái)自它的響應(yīng),甚至通過(guò)它來(lái)進(jìn)行IPC等等。我們通常將綁定它的組件成為客戶端,而稱它為服務(wù)器。

如果要?jiǎng)?chuàng)建一個(gè)支持綁定的service,我們必須要重寫它的onBind()方法。這個(gè)方法會(huì)返回一個(gè)IBinder對(duì)象,它是客戶端用來(lái)和服務(wù)器進(jìn)行交互的接口。而要得到IBinder接口,我們通常有三種方式:繼承Binder類,使用Messenger類,使用AIDL。

并且多個(gè)組件可以同時(shí)對(duì)一個(gè) Service 進(jìn)行綁定,只有在所有進(jìn)行了綁定的組件都解綁的時(shí)候,Service 才會(huì)銷毀。

service和 ?IntentService

如果是擴(kuò)建Service類的話,通常情況下我們需要新建一個(gè)用于執(zhí)行工作的新線程,因?yàn)槟J(rèn)情況下service將工作于應(yīng)用的主線程,而這將會(huì)降低所有正在運(yùn)行的Activity的性能。而IntentService就不同了。它是Service的子類,它使用工作線程來(lái)處理所有的startService請(qǐng)求。如果你不要求這個(gè)service要同時(shí)處理多個(gè)請(qǐng)求,那么繼承這個(gè)類顯然要比直接繼承Service好

IntentService已經(jīng)做了這些事:

- 創(chuàng)建默認(rèn)的工作線程,用于在應(yīng)用的主線程外執(zhí)行傳遞給 onStartCommand() 的所有 Intent

- 創(chuàng)建工作隊(duì)列,用于將一個(gè) Intent 逐一傳遞給 onHandleIntent() 實(shí)現(xiàn),這樣的話就永遠(yuǎn)不必?fù)?dān)心多線程問(wèn)題了

- 在處理完所有啟動(dòng)請(qǐng)求后停止服務(wù),從此媽媽再也不用擔(dān)心我忘記調(diào)用 stopSelf() 了

- 提供 onBind() 的默認(rèn)實(shí)現(xiàn)(返回 null)

- 提供 onStartCommand() 的默認(rèn)實(shí)現(xiàn),可將 Intent 依次發(fā)送到工作隊(duì)列和 onHandleIntent() 實(shí)現(xiàn)

因此我們只需要實(shí)現(xiàn)onHandleIntent()方法來(lái)完成具體的功能邏輯就可以了。

要注意的是,如果需要重寫其他的方法,比如onDestroy()方法,一定不要?jiǎng)h掉它的超類實(shí)現(xiàn)!因?yàn)樗某悓?shí)現(xiàn)里面也許包括了對(duì)工作線程還有工作隊(duì)列的初始化以及銷毀等操作,如果沒(méi)有了的話很容易出問(wèn)題。

如果你有讓service同時(shí)處理多個(gè)請(qǐng)求的需求,這個(gè)時(shí)候就只能去繼承Service了。這個(gè)時(shí)候就要自己去處理工作線程那些事。下面是一個(gè)官方的栗子:

~~~

public class HelloService extends Service {

private Looper mServiceLooper;

private ServiceHandler mServiceHandler;

private final class ServiceHandler extends Handler {

public ServiceHandler(Looper looper) {

super(looper);

}

@Override

public void handleMessage(Message msg) {

long endTime = System.currentTimeMillis() + 5*1000;

while (System.currentTimeMillis() < endTime) {

synchronized (this) {

try {

wait(endTime - System.currentTimeMillis());

} catch (Exception e) {

}

}

}

stopSelf(msg.arg1);

}

}

@Override

public void onCreate() {

HandlerThread thread = new HandlerThread("ServiceStartArguments",

Process.THREAD_PRIORITY_BACKGROUND);

thread.start();

mServiceLooper = thread.getLooper();

mServiceHandler = new ServiceHandler(mServiceLooper);

}

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

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() {

Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();

}

}

~~~

比起IntentService來(lái),顯然做的工作要多的多的多。但是,由于是自己處理的對(duì)onStartCommand的調(diào)用,它可以同時(shí)執(zhí)行多個(gè)請(qǐng)求——雖然官方的栗子里沒(méi)有這樣做。但是如果你想這樣做,就可以為每一個(gè)請(qǐng)求創(chuàng)建一個(gè)線程,然后立即運(yùn)行這些請(qǐng)求。

- START_NOT_STICKY : 如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù),則除非有掛起 Intent 要傳遞,否則系統(tǒng)不會(huì)重建服務(wù)。這是最安全的選項(xiàng),可以避免在不必要時(shí)以及應(yīng)用能夠輕松重啟所有未完成的作業(yè)時(shí)運(yùn)行服務(wù)。

- START_STICKY : 如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù),則會(huì)重建服務(wù)并調(diào)用 onStartCommand(),但絕對(duì)不會(huì)重新傳遞最后一個(gè) Intent。相反,除非有掛起 Intent 要啟動(dòng)服務(wù)(在這種情況下,將傳遞這些 Intent ),否則系統(tǒng)會(huì)通過(guò)空 Intent 調(diào)用 onStartCommand()。這適用于不執(zhí)行命令、但無(wú)限期運(yùn)行并等待作業(yè)的媒體播放器(或類似服務(wù))。

- START_REDELIVER_INTENT : 如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù),則會(huì)重建服務(wù),并通過(guò)傳遞給服務(wù)的最后一個(gè) Intent 調(diào)用 onStartCommand()。任何掛起 Intent 均依次傳遞。這適用于主動(dòng)執(zhí)行應(yīng)該立即恢復(fù)的作業(yè)(例如下載文件)的服務(wù)。


原文:http://www.itdecent.cn/p/d46f20695cb7

原文:http://blog.csdn.net/luoyanglizi/article/details/51980630

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容