四大組件-服務 Service

定義

服務,Android四大組件之一,屬于計算型組件

作用

提供需長期在后臺運行的的服務

特點

無用戶界面,在后臺運行,生命周期長

生命周期

Service服務有兩種啟動的方式:

  • 通過調用startService()啟動服務
  • 通過調用bindService()啟動服務
  • 通過startService()啟動服務的生命周期
    1.手動調用 startService() 方法
    2.onCreate()
    3.onStartCommand()
    4.手動調用 stopService() 方法
    5.onDestroy()

  • 通過bindService()啟動服務的生命周期
    1.手動調用 bindService() 方法
    2.onCreeate()
    3.onBind()
    4.手動調用 unbindService() 方法
    5.onUnbind()
    6.onDestroy()

Service服務的生命周期還有一種情況:先調用starService()啟動服務后,再調用bindService()進行綁定

  • 先調用startService()啟動服務,后調用bindService()綁定服務的生命周期
    1.手動調用 starService() 方法
    2.onCreate()
    3.onStartCommand()
    4.服務運行中,手動調用 bindService() 方法
    5.onBind()
    6.綁定完成,服務運行中,手動調用 unbindService() 方法
    7.onUnbind()
    8.解除綁定完成,手動調用 stopService() 方法
    9.onDestroy()

生命周期中4個手動調用的方法

1.startService()
2.stopService()
3.bindService()
4.unbindService()

1.startService()
  • 作用:啟動服務
  • 自動調用的方法:onCreate() 、onStartCommand()
  • 備注:onCreate()方法在生命周期中只調用一次,若 非首次調用 startService(),則跳過onCreate()方法直接調用onStartCommand()

onStartCommand()方法必須返回一個整數:描述在系統殺死服務后該如何繼續運行
a. START_NOT_STICKY:不會重建服務,除非還存在未發送的intent,當服務不再是必須的,并且應用程序能夠簡單的重啟那些未完成的工作時,這是避免服務運行的最安全的選項
b. START_STICKY:重建服務且調用onstartCommand(),但不會再次送入上一個intent,而是用一個null的intent來調用startCommand()。除非還有啟動服務的intent未發送完,那么這些剩下的intent會繼續發送
c. START_REDELIVER_INTENT:重建服務并用上一個已送過的intent調用onStartCommand() 。任何未發送完的intent也都會依次送入(適用于那些需要立即恢復工作的活躍服務,比如下載文件)

2.stopService()
  • 作用:停止服務
  • 自動調用的方法:onDestroy()

啟動后綁定同個Service,若無解綁的前提下調用stopService()方法是無法停止服務的

3.bindService()
  • 作用:綁定服務
  • 自動調用的方法:onCreate() 、onBind()
4.unbindService()
  • 作用:解綁服務
  • 自動調用的方法:onUnbind() 、onDestroy()

Service的分類

類型

Service可按照運行地點、運行類型、功能進行分類

  • 運行地點:本地服務 、遠程服務
  • 運行類型:前臺服務、后臺服務
  • 功能:可通信服務、不可通信服務
詳細介紹

1.按 運行地點 分類

  • 本地服務
    • 特點:運行在主線進 、 主線程終止后,服務也會停止
    • 優點:節約資源 、 通信方便(由于在同一進程因此不需要IPC和AIDL進行通信)
    • 缺點:限制性大(主線程終止后,服務也停止)
    • 應用場景:需依附某個進程的服務
  • 遠程服務
    • 特點:運行在獨立進程 、 服務常駐后臺,不受Activity影響
    • 優點:靈活(服務常駐在后臺,不受其他Activity影響)
    • 缺點:消耗資源 、 通信復雜(AIDL或IPC)
    • 應用場景:系統級別服務

2.按 運行類型 分類

  • 前臺服務

    • 特點:在通知欄顯示通知(用戶可看到)
    • 應用場景:服務使用時,需讓用戶知道并進行相關的操作(如:音樂播放服務)
  • 后臺服務

    • 特點:處于后臺的服務(用戶無法看到)
    • 應用場景:服務使用時不需要讓用戶知道并進行相關的操作(如:天氣的更新、日期同步)

3.按照 功能 分類

  • 不可通信服務
    • 特點:用startService()啟動,調用者推出后Service仍然存在
    • 應用場景:服務不需與Activity或Service通信
  • 可通信服務
    • 通過調用bindService()啟動

      • 特點:調用者退出后,隨著調用者銷毀
      • 應用場景:服務需與Activity通信,需控制服務開始時刻
      • 節約系統資源 = 第一次bindService()時才會創建服務的實例并運行:特別當服務 = Remote Service時,該效果越明顯
      • 服務只是公開一個遠程接口,供客戶端遠程調用執行方法
    • 通過調用startService() 、 bindService()啟動

      • 特點:調用者退出后 ,隨著調用者銷毀
      • 應用場景:需與Activity通信,不需要控制服務開始時刻(服務一開始就運行)
使用講解
  • 本地服務:這是最普通、最常用的后臺服務

    • 使用步驟:
      1.新建子類繼承Service類
      2.構建用于啟動Service的Intent對象
      3.調用startService()啟動Service,調用stopService()停止Service
      4.在清單配置文件 AndroidMainfest.xml里注冊Service

      //注冊Service服務
      <service android:name=".MyService"http://Service的類名
      android:label="xxxx"http:///Service的名字,若不設置,默認Service類名
      android:icon="xxxxxx"http://Service圖標
      android:permission="xxxxxx"http://申明此Service的權限,有提供了該權限的應用才能控制或連接此服務
      android:process="xxxxxx"http://表示該服務時候在另一個進程中運行(遠程服務)。默認本地服務,remote則設置遠程服務
      android:enabled="true"http://系統默認啟動
      android:exported="xxxxx"http://該服務時候能夠被其他應用程序所控制或連接
      >
      </service>
      
  • 可通訊的Service
    • 上述本地Service只能單機使用,不能用于通信

    • 通過 bindService() 方法綁定的服務能達到通信功能

    • 步驟:
      1.新建子類MyService類繼承Service類的類,并新建一個子類繼承Binder類,寫入與Acticity關聯需要的方法,創建實例。

        public class MyService extends Service {
        
        private MyBinder mBinder = new MyBinder();
        
        //.....這里省略其他方法......
        
        //新建一個子類繼承自Binder類
        class MyBinder extends Binder {
      
        public void service_connect_Activity() {
          System.out.println("Service關聯了Activity,并在Activity執行了Service的方法");
      
          }
        }
      }
      

      2.構建啟動Service的Intent對象,創建ServiceConnection的匿名類

      //創建ServiceConnection的匿名類
      private ServiceConnection connection = new ServiceConnection() {
      
      //重寫onServiceConnected()方法和onServiceDisconnected()方法
      //在Activity與Service建立關聯和解除關聯的時候調用
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
      
      //在Activity與Service解除關聯的時候調用
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
          //實例化Service的內部類myBinder
          //通過向下轉型得到了MyBinder的實例
          myBinder = (MyService.MyBinder) service;
          //在Activity調用Service類的方法
          myBinder.service_connect_Activity();
        }
      };
      
      
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
      
        Intent bindIntent = new Intent(this, MyService.class);
      
        //調用bindService()方法,以此啟動服務
        bindService(bindIntent,connection,BIND_AUTO_CREATE);
        //參數說明
              //第一個參數:Intent對象
              //第二個參數:上面創建的Serviceconnection實例
              //第三個參數:標志位
              //這里傳入BIND_AUTO_CREATE表示在Activity和Service建立關聯后自動創建Service
              //這會使得MyService中的onCreate()方法得到執行,但onStartCommand()方法不會執行
      
      
      }
      
前臺服務
  • 前臺服務于后臺服務最大的區別就在于:前臺服務在下拉通知欄有顯示通知,后臺服務沒有

  • 此外,前臺服務的優先級比較高,不會因為系統內存不足而被回收

  • 使用:在原有的Service類對onCreate()方法進行稍微修改即可

      @Override
      public void onCreate() {
        super.onCreate();
        System.out.println("執行了onCreat()");
    
        //添加下列代碼將后臺Service變成前臺Service
        //構建"點擊通知后打開MainActivity"的Intent對象
        Intent notificationIntent = new Intent(this,MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);
    
        //新建Builer對象
        Notification.Builder builer = new Notification.Builder(this);
        builer.setContentTitle("前臺服務通知的標題");//設置通知的標題
        builer.setContentText("前臺服務通知的內容");//設置通知的內容
        builer.setSmallIcon(R.mipmap.ic_launcher);//設置通知的圖標
        builer.setContentIntent(pendingIntent);//設置點擊通知后的操作
    
        Notification notification = builer.getNotification();//將Builder對象轉變成普通的notification
        startForeground(1, notification);//讓Service變成前臺Service,并在系統的狀態欄顯示出來
    
      }
    

    對于安卓8.0及以上的版本:調用 startForeground(1,notification) 方法可能會報錯

Service與Thread的區別

相同點
  • Service與Thread的作用都是進行 異步操作
不同點
  • Service是運行在 進程主線程 上(依賴于進程),只要進程在,Service就可以繼續運行。所有Activity都可以與Service關聯,獲得Binder實例后操作其中的方法。若要進行耗時操作需創建子線程
  • Thread是運行在 Activity 上的 工作線程 上(依賴于某一Activity),無法跨Activity操作子線程。當Activity銷毀后,就無法獲取到子線程的實例。

實際開發中一般會將Service與Thread相結合,即在Service中創建一個工作線程進行耗時操作。

多線程
  • 多線程的應用在開發中非常常見,主要有:
    1.繼承Thread類
    2.實現Runnable接口
    3.AsyncTask
    4.Handler
    5.HandlerThread
    6.IntentService

感謝

文章出處:簡書大神Carson_Ho
博客地址:http://www.lxweimin.com/p/d963c55c3ab9

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370