服務(wù)(Service)

概述

進程 :進程是一個應(yīng)用程序運行的載體句狼。在Android中呐粘,進程的底層是Linux管理的岗宣。Android中應(yīng)用啟動的一般過程為:Linux系統(tǒng)創(chuàng)建一個進程(pid)蚂会,進程里運行dvm,dvm里運行這個應(yīng)用
應(yīng)用程序
一個應(yīng)用程序可以對應(yīng)多個進程耗式,在Android中胁住,一個任務(wù)棧里可以有多個Activity,而Android應(yīng)用程序推出后刊咳,Android會盡量將進程保留彪见。其目的時為了下一次啟動應(yīng)用時提高啟動速度。但這種做法容易引發(fā)內(nèi)存不足的缺陷娱挨。而當內(nèi)存不足時余指,Android會自動回收部分進程,其回收的順序為:

  • 空進程 :沒有任何組件運行跷坝,所有Activity和任務(wù)棧都已被關(guān)閉的進程
  • 后臺進程 :應(yīng)用程序沒有服務(wù)處于運行狀態(tài)酵镜,并且應(yīng)用程序處于最小化的狀態(tài)。當某個程序按home鍵返回柴钻,若該程序未啟動任何服務(wù)淮韭,那么,此時進程屬于后臺進程
  • 服務(wù)進程 :服務(wù)進程是運行于后臺的沒有界面顯示的進程顿颅。Android回收內(nèi)存空間時會優(yōu)先回收后臺進程缸濒,若內(nèi)存仍然不足時才回收服務(wù)進程
  • 可見進程 :應(yīng)用UI可見,但失去焦點粱腻,不能操作庇配。一般情況下這類進程很少被回收
  • 前臺進程 :當前正在操作的進程,具有焦點绍些,可以響應(yīng)事件捞慌。一般情況下這類進程是不會被回收的。

服務(wù)概念

服務(wù)的概念最先是由微軟引入柬批。由上述回收機制可知啸澡,服務(wù)就是沒有界面但長期運行于后臺的進程。服務(wù)被回收的情況較少發(fā)生氮帐,因此嗅虏,當某一應(yīng)用程序不需要前臺UI,但需要長期運行時可以使用服務(wù)上沐。如音樂播放器皮服、后臺下載等。

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

  • 寫一個類集成Service
public class ServerDemo extends Service{
 
  @Override
  public IBinder onBind(Intent intent) {
    return null;
  }

  @Override
  public void onCreate() {
  //TODO 此方法會在服務(wù)創(chuàng)建時調(diào)用。當服務(wù)創(chuàng)建完成后龄广,將不會再調(diào)用此方法硫眯。也就是說此方法只會被調(diào)用一次
  //具體代碼寫在這里
  super.onCreate();
  }
  @Override
  public void onDestroy() {
  // TODO 此方法會在服務(wù)銷毀時被調(diào)用
  super.onDestroy();
  //service繼承了ContextWrapper類,因此择同,具有許多與Activity相同的方法两入,因此參數(shù)Context值可以是this
  //Intent intent = new Intent(this,ServerDemo.class);
  //startService(intent);    
  }
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
  // TODO 當服務(wù)被調(diào)用時執(zhí)行此方法,此方法與onStart()方法相同
    return super.onStartCommand(intent, flags, startId);
  }
}
  • 然后再清單文件中application標簽內(nèi)配置Service
    <service android:name="com.asksky.ser.ServerDemo"></service>
  • 開啟服務(wù):服務(wù)不能自己運行,需要發(fā)送Intent開啟
Intent intent = new Intent(packageContext, cls);
startService(intent);

服務(wù)的生命周期

服務(wù)只會被創(chuàng)建一次,如果重復(fù)被創(chuàng)建不會重復(fù)執(zhí)行onCreate方法
服務(wù)只會被停止一次,如果服務(wù)已經(jīng)停止不會重復(fù)執(zhí)行onDestory方法
如果服務(wù)已經(jīng)開啟,多次調(diào)用startService方法,服務(wù)只會執(zhí)行onstartCommand方法,onCreate方法不會執(zhí)行

綁定服務(wù)

在服務(wù)中,onCreate方法會在服務(wù)被創(chuàng)建時執(zhí)行,而onDestory方法會在服務(wù)銷毀時執(zhí)行.諸如此類方法都可以在一定的條件下就會被自動執(zhí)行,改變某一條件就可以達到執(zhí)行這些方法的目的.但是,服務(wù)中有可能存在自定義的方法,這些方法需要被調(diào)用必須手動new一個對象,但是,在Android中,四大組件一般是不會被手動創(chuàng)建的,因為,這些組件由Android框架創(chuàng)建,在內(nèi)可以直接使用Context等對象,若手動創(chuàng)建,這些對象就不能使用了.
為了解決四大組件不能創(chuàng)建對象敲才,但須調(diào)用其中方法這一問題裹纳,Android提供了綁定服務(wù)的機制」榻铮可以將Activity和服務(wù)綁定在一起,綁定過后就可以通過中間類來調(diào)用服務(wù)中的方法了痊夭。

綁定服務(wù)

bindService(intent, conn , BIND_AUTO_CREATE)
將當前Activity和Service綁定起來,用一個conn對象保持連接,在綁定時如果服務(wù)不存在則服務(wù)會被創(chuàng)建出來,如果服務(wù)已經(jīng)存在則直接綁定.重復(fù)綁定無效果.
綁定服務(wù)將觸發(fā)服務(wù)中的onBind方法
conn對象可以保持Activity和Service之間的綁定,當綁定狀態(tài)發(fā)生變化時其中的方法自動被調(diào)用

移除綁定服務(wù)

unbindService(conn)
將當前Activity和Serivce的綁定解除,如果服務(wù)不再被需要則銷毀(如果服務(wù)最初是被綁定時由綁定的動作而創(chuàng)建的則隨著移除綁定銷毀,如果不是則不銷毀).不可以在未綁定的情況下移除綁定.
移除綁定服務(wù)將觸發(fā)服務(wù)中的onUnBind方法
另外,Activity退出時,綁定自動解除了

具體實現(xiàn)

  • 服務(wù)類
public class MyService extends Service {
 /**
  * 在Android中,四大組件一般不能手動創(chuàng)建
  * 當需要調(diào)用以下自定義方法時,需要使用服務(wù)綁定機制
  * */
 public void show(){
  System.out.println("這是一個show()方法");
 }
/**
 * 寫一個內(nèi)部類作為service服務(wù)類與Activity類之間調(diào)用方法的中間類
 * 此類可以看做是服務(wù)類用于對外提供方法的基站
 * 可以將所有有可能被調(diào)用到的方法寫進中間類,Activity類通過此類來調(diào)用具體方法
 * */
class GetService extends Binder{
  public void getShow(){
   show();
  }
  public void otherMethod(){
   Toast.makeText(MyService.this, "所有其它需要被調(diào)用的方法都可以寫在此類中",0).show();
  }
 }
 /**
  * 綁定服務(wù)需要使用onBind方法,此方法用于將中間類返回
  * */
 @Override
 public IBinder onBind(Intent intent) {
  return new GetService();
 }
 
 @Override
 public void onCreate() {
  // TODO 創(chuàng)建服務(wù)時執(zhí)行此方法
  super.onCreate();
 }
}
  • Activity類
public class MainActivity extends ActionBarActivity {
 GetService ms = null;
 /**
  * 此時,在Activity類中調(diào)用服務(wù)類中所需要的方法,就可以通過綁定服務(wù)的機制獲取指定方法了
  * 服務(wù)方法中對外提供的獲取方法的中間類也可以被看做一個接口,使用此接口需要先獲取鏈接
  * 創(chuàng)建一個類繼承ServiceConnection
  * */
 class MyServConn implements ServiceConnection{

 @Override
 public void onServiceConnected(ComponentName name, IBinder service) {
 /** 當Service中有方法被調(diào)用時,需要用到鏈接,此方法會執(zhí)行
  * 注意必須有binder返回這個方法才有效
  * IBinder service 就是服務(wù)類中public IBinder onBind(Intent intent)方法返回的中間類
   * ComponentName name 貌似是被代理類的包名/全路徑名
  */
  ms = (GetService) service;
  System.out.println(name.toString());
  }

  @Override
  public void onServiceDisconnected(ComponentName name) {
  }
 }
@Override
 protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       Intent intent = new Intent(this, MyService.class);
       bindService(intent, new MyServConn(), BIND_AUTO_CREATE);
       //ms.getShow();此處不能在onCreate方法中調(diào)用,因為此時的中間類對象為空.
   }
 public void show(View v){
       ms.getShow();
       ms.otherMethod();
   }
}

代碼進階

上述綁定服務(wù)機制存在一個小bug:中間類所有的方法都可以被調(diào)用者調(diào)用
解決方案:

  • 寫一個接口
public interface IService {
    public void show();
}
  • 將中間類私有化,并繼承此接口
private class GetService extends Binder implements IService{
 public void getShow(){
   show();
 }
 public void otherMethod(){
   Toast.makeText(MyService.this, "所有其它需要被調(diào)用的方法都可以卸載此類中",0).show();
   }
}

  • 此時,Activity類若直接調(diào)用中間類就會報錯,此時必須調(diào)用接口,然后通過接口調(diào)用中間類中的方法,這樣,只有接口中聲明過的方法才可以被調(diào)用
IService ms = (IService) service;
ms.otherMethod();//此時若是調(diào)用此方法就會報錯

注意:在調(diào)用服務(wù)時,若使用startService()可以啟動服務(wù),且Activity退出后,service仍然可以后臺運行

但在使用綁定服務(wù)機制時,不能使用startService()方法,需要用bindService()方法來啟動服務(wù).此時,當Activity退出后,Service也會跟著退出!

解決方案

先創(chuàng)建服務(wù):
  Intent intent = new Intent(this, MyService.class);
創(chuàng)建完成后直接啟動,防止上述問題發(fā)生
  startService(intent);
當需要用到綁定服務(wù)獲取方法時,再使用bindService
  bindService(intent, new MyServConn(), BIND_AUTO_CREATE);
這樣,問題可以解決

相關(guān)鏈接:
遠程服務(wù)(AIDL)

如以上內(nèi)容有任何錯誤或補充,歡迎加QQ:1195211669 脏里,驗證信息:簡書

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市虹曙,隨后出現(xiàn)的幾起案子迫横,更是在濱河造成了極大的恐慌,老刑警劉巖酝碳,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矾踱,死亡現(xiàn)場離奇詭異,居然都是意外死亡疏哗,警方通過查閱死者的電腦和手機呛讲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來返奉,“玉大人贝搁,你說我怎么就攤上這事⊙科” “怎么了雷逆?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長污尉。 經(jīng)常有香客問我膀哲,道長,這世上最難降的妖魔是什么被碗? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任某宪,我火速辦了婚禮,結(jié)果婚禮上锐朴,老公的妹妹穿的比我還像新娘兴喂。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布瞻想。 她就那樣靜靜地躺著压真,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蘑险。 梳的紋絲不亂的頭發(fā)上滴肿,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機與錄音佃迄,去河邊找鬼泼差。 笑死,一個胖子當著我的面吹牛呵俏,可吹牛的內(nèi)容都是我干的堆缘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼普碎,長吁一口氣:“原來是場噩夢啊……” “哼吼肥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起麻车,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缀皱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后动猬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體啤斗,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年赁咙,在試婚紗的時候發(fā)現(xiàn)自己被綠了钮莲。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡彼水,死狀恐怖崔拥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情猿涨,我是刑警寧澤握童,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站叛赚,受9級特大地震影響澡绩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜俺附,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一肥卡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧事镣,春花似錦步鉴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喊递。三九已至,卻和暖如春阳似,著一層夾襖步出監(jiān)牢的瞬間骚勘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工撮奏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留俏讹,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓畜吊,卻偏偏與公主長得像泽疆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子玲献,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

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