天天看點

一個簡單的demo學習Android遠端Service(AIDL的使用)

原文位址

http://miloisbadboy.com/archives/109

這是milo很早之前寫在論壇上的一個文章,現在整理出來,milo也複習一下

一般來說Android 的四大元件都是運作在同一個程序中的,但遠端Service運作在不同的程序裡。這程序間的通信是使用了Android Binder機制。Android 中Service 有本地Service和遠端Service之分,本地Service用法比較簡單,而遠端Service用法稍微要複雜一些。下面就是一個使用AIDL的用法。

AIDL即android 接口定義語言,概念不多說,網上有太多的文章介紹概念。本文隻想說明一下aidl的用法。由于最近開發一個播放器的項目使用了aidl。aidl是解決程序間通信用的。在本例中就是Activity(即client端)與Service(即服務端)的通信。

首先,定義Aidl檔案,如Service中暴露給Activity的接口可以定義在aidl檔案中,反之也一樣。本文中,Service給Activity使用接口檔案是ServiceAIDL.aidl

<pre lang="LANGUAGE" line="1">

package com.miloisbadboy.aidl;

import com.miloisbadboy.aidl.ActivityAIDL;

/**

* Service中暴露給Activity的接口可以定義在aidl檔案中

*/

interface ServiceAIDL{

void callService();

/**

* 在Activity中注冊ActivityAIDL到Service中,使Service中可以調用ActivityAIDL中的方法

**/

void registActivityCallBack(ActivityAIDL callBack);

}

</pre>

Activity給Service中使用的ActivityAIDL.aidl

* Activity中暴露給Service的接口可以定義在aidl檔案中

interface ActivityAIDL{

void callActivity();

上面兩個aidl在會自動在gen目錄下生成對應的java檔案。

第二步,寫Service。寫一個MyService繼承于Service類,并在onBind()方法中 傳回ServiceAidl.Stub對象

具體看下面代碼

MyService.java

package com.miloisbadboy;

import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

import android.os.RemoteException;

import android.util.Log;

import android.widget.Toast;

import com.miloisbadboy.aidl.ServiceAIDL;

* 遠端服務

*/

public class MyService extends Service {

public static final String SERVICE_NAME = "com.miloisbadboy.start.MyService";

public static final String TAG = "MyService";

private ActivityAIDL activityAIDL;

@Override

public IBinder onBind(Intent intent) {

return mBinder;

}

private ServiceAIDL.Stub mBinder = new ServiceAIDL.Stub() {

@Override

public void callService() throws RemoteException {

Log.i(TAG, "Activity Call Service's method ****** callService()");

Toast.makeText(getApplicationContext(), "Call Service's method ****** callService()",

1000).show();

activityAIDL.callActivity();

}

public void registActivityCallBack(ActivityAIDL callBack) throws RemoteException {

activityAIDL = callBack;

};

MyService中有ActiviyAIDL的一個引用,此類型的執行個體是在ServiceAIDL.Stud這個代理中得到的,即是在registActivityCallBack(ActivityAIDL callBack)方法中對其指派,這個方法是在Activity中将ActivityAIDL的接口注冊到Service中去的。

在ServiceAidl.Stub mBinder = new ServiceAidl.Stub(){}裡面的callService() 和registActivityAidl(ActivityAidl activityAidl)方法就是在Activity将會被調用到的。

最後看一個Activity類

import android.app.Activity;

import android.content.ComponentName;

import android.content.Context;

import android.content.ServiceConnection;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

* 測試遠端Service

public class TestAIDLActivity extends Activity implements OnClickListener{

private static final String TAG = "TestAIDLActivity";

private Button start;

private Button stop;

private Button callService;

* service call back

*/

private ServiceAIDL serviceAIDL;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

start = (Button)findViewById(R.id.start_service);

stop = (Button)findViewById(R.id.stop_service);

callService = (Button)findViewById(R.id.call_service);

start.setOnClickListener(this);

stop.setOnClickListener(this);

callService.setOnClickListener(this);

}

public void onClick(View v) {

if(v == start){

Intent service = new Intent(MyService.SERVICE_NAME);

//綁定Service 并将ServiceConnection的執行個體傳入

bindService(service, serviceConn, Context.BIND_AUTO_CREATE);

stop.setVisibility(View.VISIBLE);

}else if(v == stop){

unbindService(serviceConn);

}else{

try {

if(serviceAIDL!=null){

serviceAIDL.callService();

}else {

Toast.makeText(this, "Service is not started!", 1000).show();

}

} catch (RemoteException e) {

e.printStackTrace();

}

private ServiceConnection serviceConn = new ServiceConnection() {

public void onServiceDisconnected(ComponentName name) {

serviceAIDL = null;

Toast.makeText(getApplication(), "Service is unbind!", 1000).show();

public void onServiceConnected(ComponentName name, IBinder service) {

serviceAIDL = ServiceAIDL.Stub.asInterface(service);

//在此将Activity暴露給Service的接口實作注冊到Service中去

serviceAIDL.registActivityCallBack(activityAidl);

* 在activity中實作ActivityAIDL接口

private ActivityAIDL activityAidl = new ActivityAIDL.Stub() {

@Override

public void callActivity() throws RemoteException {

Log.i(TAG, "callActivity()");

Toast.makeText(getApplicationContext(), "service call activity", 1000).show();

}

};

在activity中有三個按鈕分别為 start service ; stop service ;callService

各個按鈕的動作顧名思義啦。特别注意到。在Activity ServiceConnection中 會通過ServiceAIDL.Stub.asInterface(service)得到ServiceAIDL的執行個體,并且将activityAidl的引用注冊到了Service中。

在start service 按鈕事件裡,通過bindService(service, serviceConn, Context.BIND_AUTO_CREATE)将Service 與Activity綁定。

這個程式跑起來的順序是,啟動Activity後,并start service後 點選callServiceBtn,就會調用MyService中實作的callService()接口,而在callService中又調用了activityAidl即Activity的回調callActivity()方法

這樣就模拟了 Activity 與Service兩個程序間的通信,即互相調用了對方的對象。

本文隻是對Aidl的用法做了一個小小總結,算是抛磚引玉吧。

繼續閱讀