Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android應用開發入門(四十六)Service組件介紹及使用

Android應用開發入門(四十六)Service組件介紹及使用

編輯:Android開發實例

前言

  本文聊一下Android下的Service組件,對於Service組件,有點類似於Windows下的服務。Service是Android四大組件中與Activity最相似的組件,它們的區別在於:Service一直在後台運行,它沒有用戶界面。一旦Service被啟動起來之後,它就與Activity一樣,也具有自己的生命周期。

  在開發過程中,對於Activity與Service的選擇標准是:如果某個程序組件需要在運行時向用戶呈現某種界面,或者該程序需要與用戶交互,就需要使用Activity,否則就應該考慮使用Service。

  本文主要內容:

  1. Service概述
  2. Service清單文件配置
  3. Service開發步驟
  4. startService
  5. bindService
  6. Service的適用場景

 

Service概述

  與開發一個Activity類似,它需要繼承Service這個抽象類,並在實現類中,需要重寫一些回調方法,用於處理Service的生命周期各部分的操作。而Service也是繼承自Context,因此它也可以調用Context裡定義的如getResource()、getContentResolver()等方法。

  Service中定義的生命周期方法,對Service服務的開發大部分工作就圍繞以下幾個方法進行操作:

  • void onCreate():當該Service第一次被創建後將立即回調該方法。
  • void onStartCommand(Intent intent,int flags,int startId):每次通過startService()方法啟動Service時都會被回調。
  • void onDestroy():當Service被關閉前會被回調。
  • abstract IBinder onBind(Intent intent):該方法是Service子類必須實現的方法,如果不需要通過綁定的方式啟動服務,可以返回Null。
  • boolean onUnbind(Intent intent):當Service上綁定的所有客戶端都斷開連接將回調該方法。

   通過服務的啟動方式與適用范圍,可將服務分為兩類服務:

  • start:啟動服務,當一個Android組件(如一個Activity)調用startService()的時候,啟動一個服務。服務一旦啟動,就可以一直在後台運行下去,即使這個啟動它的組件被摧毀。這樣的服務模式,通常用於執行一個操作而不需要返回結果給調用者。
  • Bound:綁定服務,當一個Android組件(如一個Activity)調用bindService()。一個綁定服務提供了一個客戶端到服務端的接口,允許組件與服務之間進行交互,這樣可以實現跨進程的通信。綁定服務的生命周期默認是跟隨它的綁定組件的,但是一個綁定服務可以綁定多個Android組件,如果這些Android組件都被銷毀,那麼這個綁定服務也將被銷毀。

  雖然上面提到了服務有兩種類別,但是一個服務類所要繼承的類是一樣的,都是Service類。也就是說,一個服務,可以包含上面兩種運行方式的服務,只是與它重載的方法有關,如果重寫了onStartCommand()即支持啟動服務,如果重寫onBiind()即支持綁定服務,所以如果同時重載實現這兩個方法即可實現兩種服務。

  而對於兩種啟動方式的服務,生命周期中被回調的方法也不一樣,下圖明確說明了Service兩種情況下的生命周期:

 

清單文件的配置

  Service是Android四大組件之一,所以它也必須在 AndroidManifest清單文件中進行配置,否則系統將找不到這個服務。與Activity一樣,Service的配置也是在<application/>節點下,使用<service/>配置,其中android:name屬性為Service類。

  如果開發的服務需要被外部應用操作,還需要配置<intent-filter/>節點,但是如果僅本程序使用,則無需配置它也可以。

  如果這個服務強制僅本應用操作,可以配置<service/>節點的android:exported屬性為false,這樣即使配置了<intent-filter/>,外部應用也無法操作這個服務,android:exported屬性默認為true。

  清單文件配置示例:

  1. <application> 
  2.          <!-- 普通的服務 --> 
  3.         <service android:name=".Service1"></service> 
  4.         <!-- 可被外部應用訪問的服務 --> 
  5.         <service android:name=".Service2"> 
  6.             <intent-filter > 
  7.                 <action android:name="com.bgxt.Service2"/> 
  8.             </intent-filter> 
  9.         </service> 
  10.         <!-- 無法被外部應用訪問的服務 --> 
  11.         <service android:name=".Service3"  android:exported="false"> 
  12.             <intent-filter > 
  13.                 <action android:name="com.bgxt.Service3"/> 
  14.             </intent-filter> 
  15.         </service> 
  16.     </application> 

Service的開發步驟

  既然Service是一個與Activity類似的Android組件,所以它的開發步驟大致也為一下幾步:

  1. 開發一個服務類,需要繼承Service或者IntentService。
  2. 在AndroidManifest清單文件中注冊Service組件。
  3. 在一個Android組件中啟動這個開發的Service組件。
  4. 服務使用完成之後,需要停止這個服務。

 

啟動服務

  啟動服務必須實現Service.onStartCommond()方法。啟動服務使用startService(Intent intent)方法開啟一個服務,僅需要傳遞一個Intent對象即可,在Intent對象中指定需要啟動的服務。而使用startService()方法啟動的服務,在服務的外部,必須使用stopService()方法停止,在服務的內部可以調用stopSelf()方法停止當前服務。一旦使用startService()或者stopSelf()方法請求停止服務,系統會就會盡快銷毀這個服務。

  對於啟動服務,一旦啟動將與訪問它的組件無任何關聯,即使訪問它的組件被銷毀了,這個服務也一直運行下去,直到被銷毀!

啟動服務-示例

  下面開發一個簡單的使用startService()啟動的服務,首先開發一個服務類:

  1. package com.example.intentdemo2;  
  2.  
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.IBinder;  
  6. import android.util.Log;  
  7.  
  8. public class StartService extends Service {  
  9.     private final static String TAG = "main";  
  10.  
  11.     @Override 
  12.     public IBinder onBind(Intent arg0) {  
  13.         // 僅通過startService()啟動服務,所以這個方法返回null即可。  
  14.         return null;  
  15.     }  
  16.  
  17.     @Override 
  18.     public void onCreate() {  
  19.         super.onCreate();  
  20.         Log.i(TAG, "Service is Created");          
  21.     }  
  22.  
  23.     @Override 
  24.     public int onStartCommand(Intent intent, int flags, int startId) {  
  25.         Log.i(TAG, "Service is started");  
  26.         return super.onStartCommand(intent, flags, startId);  
  27.     }  
  28.  
  29.     @Override 
  30.     public void onDestroy() {  
  31.         Log.i(TAG, "Service is Destroyed");  
  32.         super.onDestroy();  
  33.     }  
  34.  

  雖然這個Service類沒有什麼處理邏輯,但是它包含了Service框架,在實際開發過程中,只需要在其中回調的方法中加入實際的業務實現代碼即可。下面再使用一個Activity來操作這個服務,在這個Activity中有兩個按鈕,分別用於啟動和停止這個服務。

 

  1. package com.example.intentdemo2;  
  2.  
  3. import android.app.Activity;  
  4. import android.content.ComponentName;  
  5. import android.content.Intent;  
  6. import android.os.Bundle;  
  7. import android.util.Log;  
  8. import android.view.View;  
  9. import android.widget.Button;  
  10.  
  11. public class ServiceActivity1 extends Activity {  
  12.     private Button btnSer1, btnSer2;  
  13.     private Intent service=null;  
  14.     @Override 
  15.     protected void onCreate(Bundle savedInstanceState) {  
  16.         super.onCreate(savedInstanceState);  
  17.         setContentView(R.layout.activity_service1);  
  18.         btnSer1 = (Button) findViewById(R.id.btnSer1);  
  19.         btnSer2 = (Button) findViewById(R.id.btnSer2);  
  20.         // 設置服務啟動的Intent  
  21.         service=new Intent(ServiceActivity1.this,StartService.class);  
  22.         btnSer1.setOnClickListener(new View.OnClickListener() {  
  23.  
  24.             @Override 
  25.             public void onClick(View v) {  
  26.                 // 啟動服務  
  27.                 startService(service);  
  28.             }  
  29.         });  
  30.  
  31.         btnSer2.setOnClickListener(new View.OnClickListener() {  
  32.  
  33.             @Override 
  34.             public void onClick(View v) {  
  35.                 // 停止服務  
  36.                 stopService(service);  
  37.             }  
  38.         });  
  39.     }  

 執行結果均在日志中,可以在LogCat中查看,先啟動服務,再停止服務:

綁定服務

  如果Service和宿主之間需要進行方法調用或者數據交換,則應該使用Context對象的bindService()和unbindService()方法來綁定和解除綁定服務。

  Context的bindService()方法的完整方法簽名為:

    bindService(Intent service,ServiceConnection conn,int flags)

  下面簡單介紹一下這個方法的三個參數的意義:

  • service:通過Intent指定要綁定的Service。
  • conn:一個ServiceConnection對象,該對象用於監聽訪問者與Service對象的onServiceConnected()方法。
  • flags:指定綁定時是否自動創建Service。0不自動創建、BIND_AUTO_CREATE,自動創建。

  從上面的bindService方法可以看出,綁定一個服務於宿主交互,依托於一個ServiceConnection接口,這個接口對象必須聲明在主線程中,通過實現其中的兩個方法,來實現與Service的交互,下面分別介紹一下這兩個方法:

  • void onServiceConnection(ComponentName name,IBinder service):綁定服務的時候被回調,在這個方法獲取綁定Service傳遞過來的IBinder對象,通過這個IBinder對象,實現宿主和Service的交互。
  • void onServiceDisconnected(ComponentName name):當取消綁定的時候被回調。但正常情況下是不被調用的,它的調用時機是當Service服務被意外銷毀時,例如內存的資源不足時這個方法才被自動調用。

   在使用綁定的服務的時候,該Service類必須提供一個IBinder onBind(Intent intent)方法,在綁定本地Service的情況下,onBind()方法說返回的IBinder對象會傳給宿主的ServiceConnection.onServiceConnected()方法的service參數,這樣宿主就可以通過IBinder對象與Service進行通信。實際開發中一般會繼承Binder類(IBinder的實現類)的方式實現自己的IBinder對象。

  需要注意的是,如果綁定服務提供的onBind()方法返回為Null,則也可以使用bindService()啟動服務,但不會綁定上Service,因此宿主的ServiceConnection.onServiceConnected()方法不會被執行,也就不存在於宿主與服務的交互。

綁定服務-示例

  說了這麼多綁定服務相關的內容,下面通過一個例子來實現Service的綁定與數據交互。

  開發一個Service類,用於進行綁定,在Service類中,做一個簡單的數值累加,每秒加一。

  1. package com.example.intentdemo2;  
  2.  
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.Binder;  
  6. import android.os.IBinder;  
  7. import android.util.Log;  
  8.  
  9. public class BindService extends Service {  
  10.     private final static String TAG = "main";  
  11.     private int count;  
  12.     private boolean quit;  
  13.       
  14.     private Thread thread;  
  15.     private MyBinder binder=new MyBinder();  
  16.     public class MyBinder extends Binder  
  17.     {  
  18.         // 聲明一個方法,把count暴露給外部程序。  
  19.         public int getCount(){  
  20.             return count;  
  21.         }  
  22.     }  
  23.       
  24.     @Override 
  25.     public void onCreate() {  
  26.         super.onCreate();  
  27.         Log.i(TAG, "Service is Created");  
  28.         thread=new Thread(new Runnable() {              
  29.             @Override 
  30.             public void run() {  
  31.                 // 每間隔一秒count加1 ,直到quit為true。  
  32.                 while(!quit){  
  33.                     try{  
  34.                         Thread.sleep(1000);  
  35.                     }catch(InterruptedException e){  
  36.                         e.printStackTrace();  
  37.                     }  
  38.                     count++;  
  39.                 }  
  40.             }  
  41.         });  
  42.         thread.start();  
  43.     }  
  44.       
  45.     @Override 
  46.     public boolean onUnbind(Intent intent) {  
  47.         Log.i(TAG, "Service is Unbinded");  
  48.         return true;  
  49.     }  
  50.       
  51.     @Override 
  52.     public int onStartCommand(Intent intent, int flags, int startId) {  
  53.         Log.i(TAG, "Service is started");  
  54.         return super.onStartCommand(intent, flags, startId);  
  55.     }  
  56.  
  57.     @Override 
  58.     public void onDestroy() {  
  59.         super.onDestroy();  
  60.         Log.i(TAG, "Service is Destroyed");  
  61.         this.quit=true;  
  62.           
  63.     }  
  64.       
  65.     @Override 
  66.     public IBinder onBind(Intent intent) {  
  67.         Log.i(TAG, "Service is Binded");  
  68.         return binder;  
  69.     }  

  然後使用一個Activity來綁定上面這個Service類,並且聲明一個ServiceConnection對象,用於進行數據交互。 

 

  1. package com.example.intentdemo2;  
  2.  
  3. import android.app.Activity;  
  4. import android.app.Service;  
  5. import android.content.ComponentName;  
  6. import android.content.Intent;  
  7.  
  8. import android.content.ServiceConnection;  
  9. import android.os.Bundle;  
  10. import android.os.IBinder;  
  11. import android.util.Log;  
  12. import android.view.View;  
  13. import android.widget.Button;  
  14. import android.widget.Toast;  
  15.  
  16. public class ServiceActivity2 extends Activity {  
  17.     private final String TAG = "main";  
  18.     Button bind, unbind, getServiceStatus;  
  19.     BindService.MyBinder binder;  
  20.     private ServiceConnection conn = new ServiceConnection() {  
  21.         @Override 
  22.         public void onServiceDisconnected(ComponentName name) {              
  23.             Log.i(TAG, "--Service Disconnected--");  
  24.         }  
  25.         @Override 
  26.         public void onServiceConnected(ComponentName name, IBinder service) {  
  27.             Log.i(TAG, "--Service Connected--");  
  28.             // 取得Service對象中的Binder對象  
  29.             binder = (BindService.MyBinder) service;  
  30.         }  
  31.     };  
  32.  
  33.     @Override 
  34.     protected void onCreate(Bundle savedInstanceState) {  
  35.         super.onCreate(savedInstanceState);  
  36.         setContentView(R.layout.activity_bindservice1);  
  37.           
  38.         bind = (Button) findViewById(R.id.bind);  
  39.         unbind = (Button) findViewById(R.id.unbind);  
  40.         getServiceStatus = (Button) findViewById(R.id.getServiceStatus);  
  41.           
  42.         final Intent intent = new Intent();  
  43.         // 指定開啟服務的action  
  44.         intent.setAction("com.bgxt.BindServiceDemo");  
  45.           
  46.         bind.setOnClickListener(new View.OnClickListener() {  
  47.  
  48.             @Override 
  49.             public void onClick(View v) {  
  50.                 // 綁定服務到當前activity中  
  51.                 bindService(intent, conn, Service.BIND_AUTO_CREATE);  
  52.             }  
  53.         });  
  54.         unbind.setOnClickListener(new View.OnClickListener() {  
  55.  
  56.             @Override 
  57.             public void onClick(View v) {  
  58.                 // 解除綁定  
  59.                 binder=null;  
  60.                 unbindService(conn);  
  61.             }  
  62.         });  
  63.         getServiceStatus.setOnClickListener(new View.OnClickListener() {  
  64.  
  65.             @Override 
  66.             public void onClick(View v) {  
  67.                 if(binder!=null)  
  68.                 {  
  69.                     // 通過綁定服務傳遞的Binder對象,獲取Service暴露出來的數據  
  70.                     Toast.makeText(ServiceActivity2.this,  
  71.                             "Service的Count值為" + binder.getCount(),  
  72.                             Toast.LENGTH_SHORT).show();  
  73.                     Log.i(TAG, "Service的Count值為" + binder.getCount());  
  74.                 }  
  75.                 else 
  76.                 {  
  77.                     Toast.makeText(ServiceActivity2.this,  
  78.                             "還沒綁定呢,先綁定。",  
  79.                             Toast.LENGTH_SHORT).show();  
  80.                 }                  
  81.             }  
  82.         });  
  83.     }  

 執行結果,先綁定服務,然後獲取當前服務運行時count的值,最後解除綁定,把執行過程輸出到LogCat中。

Service的選用

  相信看完以上的內容,對Android下Service組件有了一定的了解,但是對於選用startService()還是使用bindService(),有一些原則需要講明。如果僅僅是想要啟動一個後台服務長期駐留在內存中執行某項任務,那麼僅使用startService()啟動一個服務即可。但是如果想要與正在運行的服務進行交互,一種方式是使用broadcast,這個以後再介紹,另外一種方式就是使用bindService()綁定一個服務到組件上,使用broadcast的缺點是如果數據交互頻繁,容易造成性能上的問題,並且BroadcastReceiver本身執行代碼的時間不確定,也許代碼執行到一半,後面的代碼將不被執行,但是使用bindService()綁定服務即沒有這些問題。另外,如果一個服務是依托於某項應用的,那麼也最好使用綁定服務,在依托的應用啟動的時候綁定服務,這樣可以在不使用的時候避免浪費系統資源。

  源碼下載

總結

  值得注意的是,Android下的Service組件也是運行在主線程中的,所以一些Android4.0+無法在主線程上進行的操作,在Service中也必須另外開啟線程來完成,如訪問網絡,還可以使用繼承Service的子類IntentService來實現,這個內容會在之後的博客中介紹。Android系統本身還提供了大量的Service組件,開發人員可以通過這些系統Service來操作Android系統本身,這不屬於本篇博客的范疇,以後再慢慢詳解。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved