[coolxing按: 轉(zhuǎn)載請(qǐng)注明作者和出處, 如有謬誤, 歡迎在評(píng)論中指正.]
Service是android中的服務(wù)組件, 經(jīng)常用來執(zhí)行一些運(yùn)行在后臺(tái)的耗時(shí)操作. 使用一個(gè)Service需要繼承Service類, 并根據(jù)需要重寫生命周期方法. Service的生命周期如下:
|-- public abstract IBinder onBind (Intent intent): 該方法是一個(gè)抽象方法, 因此Service子類必須實(shí)現(xiàn)這個(gè)方法. 它返回一個(gè)IBinder對(duì)象, 應(yīng)用程序可以通過這個(gè)對(duì)象與Service組件通信(關(guān)于這一點(diǎn), 其后會(huì)有詳細(xì)的講解), 以bindService()方式啟動(dòng)Service時(shí)回調(diào)該方法.
|-- public void onCreate (): 當(dāng)Service第一次被創(chuàng)建后回調(diào)的方法.
|-- public void onDestroy (): Service關(guān)閉之前回調(diào)的方法.
|-- public int onStartCommand (Intent intent, int flags, int startId): 以startService(Intent intent)的方式啟動(dòng)Service時(shí), 系統(tǒng)都會(huì)回調(diào)該方法.
|-- public boolean onUnbind (Intent intent): 當(dāng)所有綁定該Service的組件都斷開連接時(shí)回調(diào)該方法.
從圖中可以看出, Service可以有兩種啟動(dòng)方式:
1. 以startService(Intent intent)的方式啟動(dòng). 此時(shí)啟動(dòng)的Service與調(diào)用者之間沒有關(guān)聯(lián), 即使調(diào)用者已經(jīng)退出, Service仍然可以繼續(xù)運(yùn)行, 而且調(diào)用者和Service之間無法進(jìn)行數(shù)據(jù)交換和通信. 如果需要停止Service的運(yùn)行, 只能調(diào)用Context類的stopService(intent)方法, 或者由Service本身調(diào)用其stopSelf()等方法.
2. 以bindService(Intent service, ServiceConnection conn, int flags)的方式啟動(dòng).
此時(shí)調(diào)用者與Service綁定在一起, 如果調(diào)用者退出, 則Service也隨之退出, 而且調(diào)用者和Service之間可以進(jìn)行數(shù)據(jù)交換或通信.
根據(jù)調(diào)用者和Service是否在一個(gè)應(yīng)用程序內(nèi), 可以將調(diào)用者和Service之間的通信分為進(jìn)程內(nèi)通信和進(jìn)程間通信.
a. 進(jìn)程內(nèi)通信. bindService(Intent service, ServiceConnection conn, int flags)方法的第二個(gè)參數(shù)為ServiceConnection對(duì)象, 最后一個(gè)參數(shù)通??梢允荢ervice.BIND_AUTO_CREATE. ServiceConnection是一個(gè)接口, 該接口包含2個(gè)方法:
|-- onServiceConnected(ComponentName name, IBinder service): 該方法在調(diào)用者和Service成功綁定之后由系統(tǒng)回調(diào).
方法中的第一個(gè)參數(shù)ComponentName是所綁定的Service的組件名稱, 而IBinder對(duì)象就是Service中onBinder()方法的返回值. 要實(shí)現(xiàn)調(diào)用者和Service之間的通信, 只需要調(diào)用IBinder對(duì)象中定義的方法即可.
|-- onServiceDisconnected(ComponentName name): 該方法在調(diào)用者解除和Service的綁定之后由系統(tǒng)回調(diào).
以下是利用Service實(shí)現(xiàn)進(jìn)程內(nèi)通信的一個(gè)例子.
首先自定義Service類:
- public class MyService extends Service {
-
- public class MyBinder extends Binder {
- /**
- * 獲取Service的運(yùn)行時(shí)間
- * @return
- */
- public long getServiceRunTime() {
- return System.currentTimeMillis() - startTime;
- }
- }
-
- private long startTime;
-
- /**
- * MyBinder是Binder的子類, 而Binder實(shí)現(xiàn)了IBinder接口.
- */
- @Override
- public IBinder onBind(Intent intent) {
- return new MyBinder();
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- startTime = System.currentTimeMillis();
- }
- }
然后在activity中綁定上述的Service:
- public class MainActivity extends Activity {
- private MyBinder binder = null;
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
-
- // 創(chuàng)建一個(gè)指向MyService的intent
- Intent intent = new Intent("cn.xing.action.my_service");
- this.bindService(intent, new MyServiceConnection(),
- Service.BIND_AUTO_CREATE);
-
- Button button = (Button) this.findViewById(R.id.button);
- button.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (binder != null) {
- Toast.makeText(getApplicationContext(), "MyService已經(jīng)運(yùn)行了" + binder.getServiceRunTime()
- + "毫秒", Toast.LENGTH_LONG).show();
- }
- }
- });
- }
-
- /**
- * 實(shí)現(xiàn)ServiceConnection接口
- *
- * @author xing
- *
- */
- private final class MyServiceConnection implements ServiceConnection {
- /**
- * 和MyService綁定時(shí)系統(tǒng)回調(diào)這個(gè)方法
- */
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- // MyService中的onBinder()方法的返回值實(shí)際上是一個(gè)MyBinder對(duì)象, 因此可以使用強(qiáng)制轉(zhuǎn)換.
- binder = (MyBinder) service;
- }
-
- /**
- * 解除和MyService的綁定時(shí)系統(tǒng)回調(diào)這個(gè)方法
- */
- @Override
- public void onServiceDisconnected(ComponentName name) {
- // 解除和MyService的綁定后, 將binder設(shè)置為null.
- binder = null;
- }
-
- }
- }
b.進(jìn)程間通信. 調(diào)用者和Service如果不在一個(gè)進(jìn)程內(nèi), 就需要使用android中的遠(yuǎn)程Service調(diào)用機(jī)制.
android使用AIDL定義進(jìn)程間的通信接口. AIDL的語法與java接口類似, 需要注意以下幾點(diǎn):
1. AIDL文件必須以.aidl作為后綴名.
2. AIDL接口中用到的數(shù)據(jù)類型, 除了基本類型, String, List, Map, CharSequence之外, 其他類型都需要導(dǎo)包, 即使兩種在同一個(gè)包內(nèi). List和Map中的元素類型必須是AIDL支持的類型.
3. 接口名需要和文件名相同.
4. 方法的參數(shù)或返回值是自定義類型時(shí), 該自定義的類型必須實(shí)現(xiàn)了Parcelable接口.
5. 所有非java基本類型參數(shù)都需要加上in, out, inout標(biāo)記, 以表明參數(shù)是輸入?yún)?shù), 輸出參數(shù), 還是輸入輸出參數(shù).
6. 接口和方法前不能使用訪問修飾符和static, final等修飾.
下面通過一個(gè)例子來演示android遠(yuǎn)程Service調(diào)用機(jī)制的各個(gè)步驟:
1. 創(chuàng)建remoteService項(xiàng)目.
2. 在cn.xing.remoteservice包下定義aidl文件--IRemoteService.aidl:
- package cn.xing.remoteservice;
- interface IRemoteService{
- int getServiceRunTime();
- }
Eclipse的ADT插件會(huì)在gen目錄的cn.xing.remoteservice包下自動(dòng)根據(jù)aidl文件生成IRemoteService接口.
接口中有一個(gè)static的抽象內(nèi)部類Stub, Stub類繼承了Binder類并實(shí)現(xiàn)了IRemoteService接口. Stub類有如下的靜態(tài)方法:
public static cn.xing.remoteservice.IRemoteService asInterface(android.os.IBinder obj)
該方法接受一個(gè)IBinder對(duì)象, 返回值是IRemoteService的instance, 通過這個(gè)instance我們就可以調(diào)用IRemoteService中定義的方法了.
3. 在remoteService項(xiàng)目的cn.xing.remoteservice包下創(chuàng)建遠(yuǎn)程服務(wù)類RemoteService:
- public class RemoteService extends Service {
- private long startTime;
-
- /**
- * IRemoteService.Stub類實(shí)現(xiàn)了IBinder和IRemoteService接口
- * 因此Stub的子類對(duì)象可以作為onBinder()方法的返回值.
- * @author xing
- *
- */
- public class MyBinder extends IRemoteService.Stub {
- @Override
- public long getServiceRunTime() throws RemoteException {
- return System.currentTimeMillis() - startTime;
- }
- };
-
- @Override
- public IBinder onBind(Intent intent) {
- return new MyBinder();
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- startTime = System.currentTimeMillis();
- }
- }
4. 創(chuàng)建一個(gè)新的android項(xiàng)目invokeRemoteService, 并復(fù)制remoteService項(xiàng)目中的aidl文件(連同包結(jié)構(gòu)一起復(fù)制)到invokeRemoteService項(xiàng)目中.
5. 在invokeRemoteService項(xiàng)目中綁定遠(yuǎn)程服務(wù), 并調(diào)用遠(yuǎn)程方法.
- public class MainActivity extends Activity {
- private IRemoteService iRemoteService = null;
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
-
- // 創(chuàng)建一個(gè)指向RemoteService的intent
- Intent intent = new Intent("cn.xing.action.remote_service");
- this.bindService(intent, new MyServiceConnection(),
- Service.BIND_AUTO_CREATE);
-
- Button button = (Button) this.findViewById(R.id.button);
- button.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (iRemoteService != null) {
- try {
- Toast.makeText(getApplicationContext(), "MyService已經(jīng)運(yùn)行了" + iRemoteService.getServiceRunTime()
- + "毫秒", Toast.LENGTH_LONG).show();
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- }
- });
- }
-
- /**
- * 實(shí)現(xiàn)ServiceConnection接口
- *
- * @author xing
- *
- */
- private final class MyServiceConnection implements ServiceConnection {
- /**
- * 和RemoteService綁定時(shí)系統(tǒng)回調(diào)這個(gè)方法
- */
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- // 此處不能使用強(qiáng)制轉(zhuǎn)換, 應(yīng)該調(diào)用Stub類的靜態(tài)方法獲得IRemoteService接口的實(shí)例對(duì)象
- iRemoteService = IRemoteService.Stub.asInterface(service);
- }
-
- /**
- * 解除和RemoteService的綁定時(shí)系統(tǒng)回調(diào)這個(gè)方法
- */
- @Override
- public void onServiceDisconnected(ComponentName name) {
- // 解除和RemoteService的綁定后, 將iRemoteService設(shè)置為null.
- iRemoteService = null;
- }
- }
- }
附件中包含進(jìn)程內(nèi)通信和進(jìn)程間通信例子的源碼, 需要的朋友可自行下載查看.