Android ApiDemos示例解析(38):App->Service->Foreground Service Controller

和Windows中的Service類似,Android系統也提供瞭一種稱為“Service”的組件通常在後臺運行。Activity 可以用來啟動一個Service,Service啟動後可以保持在後臺一直運行,即使啟動它的Activity退出或是切換到別的應用Service也能保持運行狀態。

Service 可以以兩種形式存在:

Started 當一個如Activity使用startService()來啟動一個Service,一旦Service啟動後,就不受啟動它的Activity控制,可以在後臺長期運行,通常這種Service在後臺執行某個費時操作(如下載文件)不會向啟動它的Activity返回結果。
Bound 為Activity或是其它程序部件使用bindService()來啟動Service。Bound Service提供瞭一種Client/Service方法允許調用Service的Activity與Service進行交互:發送請求,取得結果,並支持進程間通信。 一般Bound Service的生命周期和啟動它的Activity相同,多個Activity可以同時綁定一個Service。 當所有Activity 都斷開與Service之間的綁定時。Service自動結束。
雖然Service可以有上述兩種表現形式,這隻是為瞭說明上的方便,實際上同一個Service可以同時以兩種方式存在,隻要實現兩種方法所定義的接口函數就可以瞭。

創建一個Service,首先需要定義一個Service的子類,然後根據需要重載Service定義的一些核心方法:

onStartCommand() 當一個Activity調用startService時,Android系統會調用Service的onStartCommand()方法, 前面說過使用startService啟動的Service會在後臺長期運行,不受啟動它的Activity控制,因此應用程序有責任來停止Service,Service也可以調用stopSelf來停止自身。
onBind() 當一個Activity 使用bindService()來綁定Service時Android系統會調用Service的onBind方法,onBind需要返回一個IBind對象給調用者(Client)。Client然後可以使用IBind提供的方法來使用Service。
onCreate() Service第一次創建時被調用,和Activity的onCreate類似。
onDestroy() Service退出時調用。
定義瞭Service類和實現相應方法後,和Activity一樣,也需要在AndroidManifest.xml中定義這個Service:

<manifest … >

<application … >
<service android:name=”.ExampleService” />

< /application>
< /manifest>

和Activity一樣,也可以為Service定義Intent Filter,如果你不想共享這個Service,可以將android:exported屬性定義為false。

通常情況下Service在後臺運行,當Android也支持Service運行在前臺,運行在前臺的Service必須在屏幕頂端的Status Bar提供一個Notification以提示用戶有Service在運行。比如提供個Media Player使用的Service運行在前臺,而在標題欄顯示當前曲目。

本例Foreground Service Controller就顯示瞭一個在前臺運行的Service, 前臺運行的Service可以通過調用startForeground()使Service在前臺運行。stopForeground停止前臺運行,但Service本身不會停止。 startForeground,stopForeground是從2.0開始支持的,之前的版本采用setForeground。

本例為瞭支持2.0之前和2.0之後的版本,采用瞭Reflection的方法來來查找當前版本是否含有startForeground和stopForeground,如果有則調用,沒有則還是使用setForeground。

如果找到的話,以下的變量用來存儲startForeground和stopForeground方法。和本例Service不相關,就不詳述瞭。隻要知道startForegroundCompat 和stopForegroundCompat的功能就是startForeground 和stopForeground就行瞭。

[java] view plaincopyprint?
private static final Class[] mStartForegroundSignature = new Class[] { 
 int.class, Notification.class}; 
private static final Class[] mStopForegroundSignature = new Class[] { 
 boolean.class}; 
  
private Method mStartForeground; 
private Method mStopForeground; 
private Object[] mStartForegroundArgs = new Object[2]; 
private Object[] mStopForegroundArgs = new Object[1]; 
private static final Class[] mStartForegroundSignature = new Class[] {
 int.class, Notification.class};
private static final Class[] mStopForegroundSignature = new Class[] {
 boolean.class};
 
private Method mStartForeground;
private Method mStopForeground;
private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1];
下面來看看ForegroundService的代碼:
首先是必須作為Service的子類:

[java] view plaincopyprint?
public class ForegroundService extends Service 
public class ForegroundService extends Service
因為是作為“Started” Service來設計的,因此需定義onStartCommand ,同樣onStartCommand也是在Android 2.0之後添加的,2.0之前為onStart。本例為瞭支持所有版本,兩個方法對實現瞭,對應2.0之後的版本,隻會調用onStartCommand,2.0之前的隻會調用onStart

[java] view plaincopyprint?
// This is the old onStart method that  
// will be called on the pre-2.0 platform.  
// On 2.0 or later we override onStartCommand() so this  
// method will not be called.  
@Override 
public void onStart(Intent intent, int startId) { 
handleCommand(intent); 

  
@Override 
public int onStartCommand(Intent intent, 
 int flags, int startId) { 
handleCommand(intent); 
// We want this service to  
//continue running until it is explicitly  
// stopped, so return sticky.  
return START_STICKY; 

// This is the old onStart method that
// will be called on the pre-2.0 platform.
// On 2.0 or later we override onStartCommand() so this
// method will not be called.
@Override
public void onStart(Intent intent, int startId) {
handleCommand(intent);
}
 
@Override
public int onStartCommand(Intent intent,
 int flags, int startId) {
handleCommand(intent);
// We want this service to
//continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
onStartCommand 可以有返回結果,這個返回值告訴Android系統當這個Service被Kill之後(比如當系統內存不足時)後續操作。START_STICKY 表示系統Kill這個Service之後,如果重新創建這個Service時在調用onStartCommand ,不會將最後的Intent作為參數傳入,也就是說intent=null. START_REDELIVER_INTENT則會傳入被殺前未處理的最後一個Intent。

本Service不作為Bind Service ,因此通過一個空實現:

[java] view plaincopyprint?
@Override 
public IBinder onBind(Intent intent) { 
return null; 

@Override
public IBinder onBind(Intent intent) {
return null;
}
最後看看如何啟動/停止這個Service, Controller 是作為這個Service的控制類來實現的,提供瞭前臺啟動,後臺啟動,和停止Service操作:

[java] 
private OnClickListener mForegroundListener 
 = new OnClickListener() { 
 public void onClick(View v) { 
 Intent intent 
 = new Intent(ForegroundService.ACTION_FOREGROUND); 
 intent.setClass(Controller.this, 
 ForegroundService.class); 
 startService(intent); 
 } 
}; 
  
private OnClickListener mBackgroundListener 
 = new OnClickListener() { 
 public void onClick(View v) { 
 Intent intent 
 = new Intent(ForegroundService.ACTION_BACKGROUND); 
 intent.setClass(Controller.this, 
 ForegroundService.class); 
 startService(intent); 
 } 
}; 
  
private OnClickListener mStopListener = new OnClickListener() { 
 public void onClick(View v) { 
 stopService(new Intent(Controller.this, 
 ForegroundService.class)); 
 } 
}; 
private OnClickListener mForegroundListener
 = new OnClickListener() {
 public void onClick(View v) {
 Intent intent
 = new Intent(ForegroundService.ACTION_FOREGROUND);
 intent.setClass(Controller.this,
 ForegroundService.class);
 startService(intent);
 }
};
 
private OnClickListener mBackgroundListener
 = new OnClickListener() {
 public void onClick(View v) {
 Intent intent
 = new Intent(ForegroundService.ACTION_BACKGROUND);
 intent.setClass(Controller.this,
 ForegroundService.class);
 startService(intent);
 }
};
 
private OnClickListener mStopListener = new OnClickListener() {
 public void onClick(View v) {
 stopService(new Intent(Controller.this,
 ForegroundService.class));
 }
};


作者:mapdigit
 

 

發佈留言