很多情況下,一些與用戶很少需要產生交互的應用程序,我們一般讓它們在後臺運行就行了,而且在它們運行期間我們仍然能運行其他的應用。
爲了處理這種後臺進程,Android引入了Service的概念。Service在Android中是一種長生命週期的組件,它不實現任何用戶界面。最 常見的例子如:媒體播放器程序,它可以在轉到後臺運行的時候仍然能保持播放歌曲;或者如文件下載程序,它可以在後臺執行文件的下載。
讓我們來看下如何創建Service:
創建一個Service
Android中已經定義了一個 ‘Service’類,所有其他的Service都繼承於該類。Service類中定義了一系列的生命週期相關的方法,如: onCreate(), onStart(), onDestroy()。參見下例:
package com.wissen.testApp.service;
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, “Service created…”, Toast.LENGTH_LONG).show();
}
@Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, “Service destroyed…”, Toast.LENGTH_LONG).show();
}
}
上例中的這個Service主要做了這些事:當服務創建和銷燬時通過界面消息提示用戶。
如Android中的其它部件一樣, Service也會和一系列Intent關聯。Service的運行入口需要在AndroidManifest.xml中進行配置,如下:
<service class=”.service.MyService”>
<intent-filter>
<action android:value=”com.wissen.testApp.service.MY_SERVICE” />
</intent-filter>
</service>
之後我們的Service就可以被其他代碼所使用了。
使用Service:
應用程序可以通過調用 Context.startService方法來啓動Service。如果當前沒有指定的Service實例被創建,則該方法會調用 Service的onCreate方法來創建一個實例;否則調用Service的onStart方法。參見下列代碼:
..
Intent serviceIntent = new Intent();
serviceIntent.setAction(”com.wissen.testApp.service.MY_SERVICE”);
startService(serviceIntent);
..
以上代碼調用了startService方法,Service會持續運行,直到調用stopService()或stopSelf()方法。
還有另一種綁定Service的方式:
…
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(”INFO”, “Service bound “);
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
Log.i(”INFO”, “Service Unbound “);
}
};
bindService(new Intent(”com.wissen.testApp.service.MY_SERVICE”), conn, Context.BIND_AUTO_CREATE);
…
當應用程序綁定一個Service後,該應用程序和Service之間就能進行互相通信,通常,這種通信的完成依靠於我們定義的一些接口,請看下例:
package com.wissen.testApp;
public interface IMyService {
public int getStatusCode();
}
private int statusCode;
private MyServiceBinder myServiceBinder = new MyServiceBinder();
@Override
public IBinder onBind(Intent intent) {
return myServiceBinder;
}
public int getStatusCode() {
return statusCode;
}
}
…
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IMyService myService = (IMyService) service;
statusCode = myService.getStatusCode();
Log.i(”INFO”, “Service bound “);
}
…
};
或者,你也可以通過使用ServiceListener接口來達成相同的目的。
與遠程Service通信(進程間Service通信):
如何兩個進程間的Service需要進行通信,則需要把對象序列化後進行互相發送。
Android提供了一個 AIDL (Android接口定義語言)工具來處理序列化和通信。這種情況下Service需要以aidl文件的方式提供服務接口,AIDL工具將生成一個相應的java接口,並且在生成的服務接口中包含一個功能調用的stub服務樁類。Service的實現類需要去繼承這個 stub服務樁類。Service的onBind方法會返回實現類的對象,之後你就可以使用它了,參見下例:
先創建一個IMyRemoteService.aidl文件,內容如下:
package com.wissen.testApp;
interface IMyRemoteService {
int getStatusCode();
}
如果你正在使用eclipse的 Android插件,則它會根據這個aidl文件生成一個Java接口類。生成的接口類中會有一個內部類Stub類,你要做的事就是去繼承該Stub類:
package com.wissen.testApp;
class RemoteService implements Service {
int statusCode;
@Override
public IBinder onBind(Intent arg0) {
return myRemoteServiceStub;
}
private IMyRemoteService.Stub myRemoteServiceStub = new IMyRemoteService.Stub() {
public int getStatusCode() throws RemoteException {
return 0;
}
};
…
}
當客戶端應用連接到這個Service時,onServiceConnected方法將被調用,客戶端就可以獲得IBinder對象。參看下面的客戶端onServiceConnected方法:
…
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IMyRemoteService myRemoteService = IMyRemoteService.Stub.asInterface(service);
try {
statusCode = myRemoteService.getStatusCode();
} catch(RemoteException e) {
// handle exception
}
Log.i(”INFO”, “Service bound “);
}
…
};
權限:
我們可以在AndroidManifest.xml文件中使用<service>標籤來指定Service訪問的權限:
<service class=”.service.MyService” android:permission=”com.wissen.permission.MY_SERVICE_PERMISSION”>
<intent-filter>
<action android:value=”com.wissen.testApp.service.MY_SERVICE” />
</intent-filter>
</service>
之後應用程序要訪問該Service的話就需要使用<user-permission>標籤來指定相應的權限:
<uses-permission android:name=”com.wissen.permission.MY_SERVICE_PERMISSION”>
</uses-permission>