Android 之 Service(一)啟動(dòng),綁定服務(wù)

一、介紹

Service(服務(wù))一個(gè)運(yùn)行在后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行的操作組件,它不提供任何用戶界面,作為與Activity同級(jí)的組件,它依舊是運(yùn)行在主線程中。
其它組件可以啟動(dòng)一個(gè)Service,當(dāng)這個(gè)Service啟動(dòng)之后便會(huì)在后臺(tái)執(zhí)行,這里需要注意,由于是在主線程中,所以我們需要另外開(kāi)啟一個(gè)線程來(lái)執(zhí)行我們的耗時(shí)操作。
此外,一個(gè)組件還可以與一個(gè)Service進(jìn)行綁定來(lái)實(shí)現(xiàn)組件之間的交互,甚至可以執(zhí)行IPC(Inter-Process Communication)進(jìn)程間通信。
Service可以在后臺(tái)執(zhí)行很多任務(wù),比如處理網(wǎng)絡(luò)事務(wù),播放音樂(lè),文件讀寫(xiě)或者與一個(gè)內(nèi)容提供者交互,等等。

二、服務(wù)分類

本地服務(wù)(Local)
該服務(wù)依附在主進(jìn)程上而不是獨(dú)立的進(jìn)程,這樣在一定程度上節(jié)約了資源,另外本地服務(wù)因?yàn)槭窃谕贿M(jìn)程因此不需要IPC,也不需要AIDL。相應(yīng)bindService會(huì)方便很多,當(dāng)主進(jìn)程被Kill后,服務(wù)便會(huì)終止。一般使用在音樂(lè)播放器播放等不需要常駐的服務(wù)。

遠(yuǎn)程服務(wù)(Remote Service)
該服務(wù)是獨(dú)立的進(jìn)程,對(duì)應(yīng)進(jìn)程名格式為所在包名加上你指定的android:process字符串。一般定義方式 android:process=":service" 由于是獨(dú)立的進(jìn)程,因此在Activity所在進(jìn)程被Kill的時(shí)候,該服務(wù)依然在運(yùn)行,不受其他進(jìn)程影響,有利于為多個(gè)進(jìn)程提供服務(wù)具有較高的靈活性。由于是獨(dú)立的進(jìn)程,會(huì)占用一定資源,并且使用AIDL進(jìn)行IPC比較麻煩。一般用于系統(tǒng)的Service,這種Service是常駐的。

三、Service啟動(dòng)方式

startService啟動(dòng)的服務(wù)
用于啟動(dòng)一個(gè)服務(wù)執(zhí)行后臺(tái)任務(wù),不與組件進(jìn)行通信,停止服務(wù)使用stopService。 當(dāng)一個(gè)應(yīng)用組件比如activity通過(guò)調(diào)用startService()來(lái)啟動(dòng)一個(gè)服務(wù)的時(shí)候,服務(wù)便處于啟動(dòng)狀態(tài)。一旦啟動(dòng),服務(wù)可以在后臺(tái)無(wú)限期地運(yùn)行下去,即使當(dāng)啟動(dòng)它的組件已經(jīng)銷毀。通常情況下,一個(gè)啟動(dòng)的service執(zhí)行一個(gè)單一的操作并且不會(huì)返回任何結(jié)果給調(diào)用者。

bindService啟動(dòng)的服務(wù)
用于啟動(dòng)的服務(wù)需要進(jìn)行通信。停止服務(wù)使用unbindService。 當(dāng)一個(gè)應(yīng)用組件通過(guò)調(diào)用bindService()來(lái)與一個(gè)服務(wù)綁定時(shí),服務(wù)便處于綁定狀態(tài)。一個(gè)綁定的服務(wù)提供了一個(gè)客戶端-服務(wù)器端接口來(lái)允許組件與服務(wù)進(jìn)行交互,發(fā)送請(qǐng)求,得到結(jié)果甚至通過(guò)IPC進(jìn)程間通信來(lái)完成操作。只有當(dāng)其它組件與服務(wù)進(jìn)行綁定時(shí),服務(wù)才會(huì)處于綁定狀態(tài)。多個(gè)組件可以同時(shí)與服務(wù)綁定,但是當(dāng)他們?nèi)慷冀獬壎〞r(shí),服務(wù)就會(huì)銷毀。

四、服務(wù)的生命周期

Service不同啟動(dòng)方式生命周期.png

1.StartService:
一個(gè)Service被使用startService方法啟動(dòng),不管是否調(diào)用了bindService(綁定服務(wù))或unbindService(解除綁定服務(wù))到該Service,該Service都會(huì)在后臺(tái)運(yùn)行并不受影響。一個(gè)Service被使用startService方法啟動(dòng)多少次,onCreate方法只會(huì)調(diào)用一次,onStartCommand方法將會(huì)被調(diào)用多次(與startService的次數(shù)一致),且系統(tǒng)只會(huì)創(chuàng)建一個(gè)Service實(shí)例(結(jié)束該Service也只需要調(diào)用一次stopService),該Service會(huì)一直在后臺(tái)運(yùn)行直至調(diào)用stopService或調(diào)用自身的stopSelf方法。

注:在系統(tǒng)資源不足的情況下,服務(wù)有可能被系統(tǒng)結(jié)束(kill);

2.BindService:
如果一個(gè)Service在某個(gè)Activity中被調(diào)用bindService方法啟動(dòng),不論bindService被調(diào)用幾次,Service的onCreate方法只會(huì)執(zhí)行一次,同時(shí)onStartCommand方法始終不會(huì)調(diào)用。當(dāng)建立連接后,Service會(huì)一直運(yùn)行,除非調(diào)用unbindService來(lái)接觸綁定、斷開(kāi)連接或調(diào)用該Service的Context不存在了(如Activity被Finish——即通過(guò)bindService啟動(dòng)的Service的生命周期依附于啟動(dòng)它的Context),系統(tǒng)在這時(shí)會(huì)自動(dòng)停止該Service。

3.StartService AND BindService:
當(dāng)一個(gè)Service在被啟動(dòng)(startService 的同時(shí)又被綁定(bindService ),該Service將會(huì)一直在后臺(tái)運(yùn)行,并且不管調(diào)用幾次,onCreate方法始終只會(huì)調(diào)用一次,onStartCommand的調(diào)用次數(shù)與startService 調(diào)用的次數(shù)一致(使用bindService 方法不會(huì)調(diào)用onStartCommand)。同時(shí),調(diào)用unBindService 將不會(huì)停止Service,必須調(diào)用stopService 或Service自身的stopSelf 來(lái)停止服務(wù)。

官方原文:
If you do allow your service to be started and bound,then when then service has been started,the System does not destory the service when all clients unbind.Instead,you must explicitly stop the service,by calling stopSelf() or stopService().
如果你同意你的服務(wù)被開(kāi)啟和綁定,然后當(dāng)服務(wù)被開(kāi)啟的時(shí)候,當(dāng)所有的客戶端都解除對(duì)服務(wù)的綁定android操作系統(tǒng)也不會(huì)銷毀這個(gè)服務(wù),相反的你必須顯示的調(diào)用stopSelf()或者stopService()方法來(lái)停止服務(wù)。
什么情況下使用:
如果你想要與正在運(yùn)行的Service取得聯(lián)系,那么有兩種方法,一種是使用廣播,另外一種方法就是使用bindService來(lái)建立聯(lián)系,前者的缺點(diǎn)是如果交流較為頻繁,容易造成性能上的問(wèn)題,并且BroadcastReceiver本身執(zhí)行代碼的時(shí)間是很短的(也許執(zhí)行到一半,后面的代碼便不會(huì)執(zhí)行),而后者則沒(méi)有這些問(wèn)題,因此我們肯定選擇使用bindService(這個(gè)時(shí)候你便同時(shí)在使用startService和bindService了,這在Activity中更新Service的某些運(yùn)行狀態(tài)是相當(dāng)有用的)。

4.停止Service:
當(dāng)一個(gè)服務(wù)被終止(stopService 、stopSelf 、unbindService )時(shí),onDestory方法將會(huì)被調(diào)用——所以我們需要在該方法中清除一些工作(依附該Service生命周期上的,比如:停止在Service中創(chuàng)建并運(yùn)行的線程)。

特別注意:
1.在使用startService 方法啟動(dòng)服務(wù)后,一定要調(diào)用stopService 方法來(lái)停止該服務(wù)(同上,可以在Activity的onDestory中來(lái)停止服務(wù));

2.在某處調(diào)用bindService 綁定Service的時(shí)候,要在對(duì)應(yīng)的某處調(diào)用 unbindService 來(lái)解除綁定(如在Activity中綁定了Service,可以在onDestory中來(lái)解除綁定——雖然綁定的Service會(huì)在Activity結(jié)束時(shí)自動(dòng)解除、停止);

3.如果同時(shí)使用startService 與bindService 方法啟動(dòng)Service,需要終止該Service時(shí),要調(diào)用stopService 和unbindService 方法(unbindService 依附于啟動(dòng)它的Context,startServicec 并不依附于啟動(dòng)它的Context。如果先調(diào)用unbindService ,這時(shí)服務(wù)并不會(huì)被終止,當(dāng)調(diào)用stopService 后,服務(wù)才會(huì)被終止;如果先調(diào)用stopService ,服務(wù)也不會(huì)被終止,當(dāng)調(diào)用unbindService 或者之前調(diào)用bindService 的Context不存在了(如Activity被finish掉了)服務(wù)才會(huì)自動(dòng)停止);

4.當(dāng)手機(jī)屏幕發(fā)生旋轉(zhuǎn)時(shí),如果Activity設(shè)置的是自動(dòng)旋轉(zhuǎn)的話,在旋轉(zhuǎn)的過(guò)程中,Activity會(huì)重新創(chuàng)建,那么之前通過(guò)bindService 建立的連接便會(huì)斷開(kāi)(之前的Context不存在了),服務(wù)也會(huì)被自動(dòng)停止。

五、Service使用

1.創(chuàng)建服務(wù)

public class MyService extends Service{
 
    //服務(wù)創(chuàng)建
    @Override
    public void onCreate() {
        super.onCreate();
    }
    
    // 服務(wù)啟動(dòng)
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
    
    //服務(wù)銷毀
    @Override
    public void onDestroy() {
        stopSelf(); //自殺服務(wù)
        super.onDestroy();
    }
   
    //綁定服務(wù)
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }
    // IBinder是遠(yuǎn)程對(duì)象的基本接口,是為高性能而設(shè)計(jì)的輕量級(jí)遠(yuǎn)程調(diào)用機(jī)制的核心部分。但它不僅用于遠(yuǎn)程 
    // 調(diào)用,也用于進(jìn)程內(nèi)調(diào)用。這個(gè)接口定義了與遠(yuǎn)程對(duì)象交互的協(xié)議。
    // 不要直接實(shí)現(xiàn)這個(gè)接口,而應(yīng)該從Binder派生。 
    // Binder類已實(shí)現(xiàn)了IBinder接口 
    class MyBinder extends Binder { 
            /** * 獲取Service的方法 * @return 返回PlayerService */ 
            public MyService getService(){ 
                   return MyService.this;   
            } 
     }
}

如果你才用的是 startService的方式那么 onBind方法可以忽略
2.注冊(cè)服務(wù)

 <service
            android:name=".service.MyService"
            android:exported="true"
            android:label="MyService" />

3.開(kāi)啟服務(wù)
start:

public class MyActivity extends AppCompatActivity{
  private Intent intent;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    intent = new Intent(this, MyService.class);
    startService(intent);// 啟動(dòng)服務(wù)
  }
  @Override
  protected void onDestroy() {
    super.onDestroy();
    stopService(intent);// 在退出Activity時(shí)停止該服務(wù),如果希望常駐后臺(tái),可以不進(jìn)行停止。
  }
}

bind

public class MyActivity extends Activity{
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
      //綁定目標(biāo)Service
    Intent intent = new Intent(this, MyActivity.class);
    bindService(intent, serviceConnection,  Context.BIND_AUTO_CREATE);
  }
  @Override
  protected void onDestroy() {
    super.onDestroy();
    unbindService(serviceConnection);// 解除綁定,斷開(kāi)連接
  }
  // 在Activity中,我們通過(guò)ServiceConnection接口來(lái)取得建立連接與連接意外丟失的回調(diào)
  ServiceConnection serviceConnection = new ServiceConnection() {            @Override
    public void onServiceConnected(ComponentName name, IBinder service){
      // 建立連接
      // 獲取服務(wù)的操作對(duì)象
           MyService.MyBinder binder = (MyService.MyBinder)service;
           binder.getService();// 獲取到的Service即MyService
    } 
    @Override
    public void onServiceDisconnected(ComponentName name) {
      // 連接斷開(kāi)
    }
  };
}

綁定服務(wù),一般涉及到組件或進(jìn)程之間的通信,既然需要通信,那么我們肯定需要一個(gè)連接,這里ServiceConnection就是我們所需要的連接,通過(guò)Ibinder的傳遞,我們可以獲取到Service的Ibinder對(duì)象,從而進(jìn)行相關(guān)操作。

六、粘性服務(wù)、非粘性服務(wù)

關(guān)于粘性服務(wù),這里需要提到 Service的onStartCommand返回值

START_STICKY:
sticky的意思是“粘性的”。使用這個(gè)返回值時(shí),我們啟動(dòng)的服務(wù)跟應(yīng)用程序"粘"在一起,如果在執(zhí)行完onStartCommand后,服務(wù)被異常kill掉,系統(tǒng)會(huì)自動(dòng)重啟該服務(wù)。當(dāng)再次啟動(dòng)服務(wù)時(shí),傳入的第一個(gè)參數(shù)將為null;
START_NOT_STICKY:
“非粘性的”。使用這個(gè)返回值時(shí),如果在執(zhí)行完onStartCommand后,服務(wù)被異常kill掉,系統(tǒng)不會(huì)自動(dòng)重啟該服務(wù)。
START_REDELIVER_INTENT:
重傳Intent。使用這個(gè)返回值時(shí),如果在執(zhí)行完onStartCommand后,服務(wù)被異常kill掉,系統(tǒng)會(huì)自動(dòng)重啟該服務(wù),并將Intent的值傳入。

七、AndroidManifest.xml中Service元素常見(jiàn)屬性

andorid:name

服務(wù)類名。可以是完整的包名+類名。也可使用. 代替包名。

adroid:exported

其他應(yīng)用能否訪問(wèn)該服務(wù),如果不能,則只有本應(yīng)用或有相同用戶ID的應(yīng)用能訪問(wèn)。默認(rèn)為false。

android:enabled

標(biāo)識(shí)服務(wù)是否可以被系統(tǒng)實(shí)例化。true--系統(tǒng)默認(rèn)啟動(dòng),false--不啟動(dòng)。(默認(rèn)值為true)

android:label

顯示給用戶的服務(wù)名稱。如果沒(méi)有進(jìn)行服務(wù)名稱的設(shè)置,默認(rèn)顯示服務(wù)的類名。

android:process

服務(wù)所運(yùn)行的進(jìn)程名。默認(rèn)是在當(dāng)前進(jìn)程下運(yùn)行,與包名一致。如果進(jìn)行了設(shè)置,將會(huì)在包名后加上設(shè)置的集成名。如果名稱設(shè)置為冒號(hào): 開(kāi)頭,一個(gè)對(duì)應(yīng)用程序私有的新進(jìn)程會(huì)在需要時(shí)和運(yùn)行到這個(gè)進(jìn)程時(shí)建立。如果名稱為小寫(xiě)字母開(kāi)頭,服務(wù)會(huì)在一個(gè)相同名字的全局進(jìn)程運(yùn)行,如果有權(quán)限這樣的話。這允許不同應(yīng)用程序的組件可以分享一個(gè)進(jìn)程,減少了資源的使用。

android:icon

服務(wù)的圖標(biāo)。

android:permission

申請(qǐng)使用該服務(wù)的權(quán)限,如果沒(méi)有配置下相關(guān)權(quán)限,服務(wù)將不執(zhí)行,使用startService() 、bindService() 方法將都得不到執(zhí)行。

關(guān)于服務(wù),當(dāng)我們?cè)趹?yīng)用開(kāi)發(fā)中,如果需要長(zhǎng)時(shí)間的在后臺(tái)運(yùn)行,獨(dú)立完成某一些事情的情況下,請(qǐng)使用Service!

此文綜合:http://www.lxweimin.com/p/1e49e93c3ec8 以及自己的一些問(wèn)題看法,用作學(xué)習(xí),回顧之用。

Service 前臺(tái)服務(wù)
請(qǐng)參看紫豪 http://www.lxweimin.com/p/5505390503fa

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,263評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,946評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,708評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,409評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,774評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,641評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,872評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,650評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

推薦閱讀更多精彩內(nèi)容