在Andorid平台中,各个组件运行在自己的进程中,他们之间是不能相互访问的,但是在程序之间是不可避免的要传递一些对象,在进程之间相互通信。为了实现进程之间的相互通信,Andorid采用了一种轻量级的实现方式RPC(Remote Procedure Call 远程进程调用)来完成进程之间的通信,并且Android通过接口定义语言(Andorid Interface Definition Language ,AIDL)来生成两个进程之间相互访问的代码,例如,你在Activity里的代码需要访问Service中的一个方法,那么就可以通过这种方式来实现了。
AIDL是Android的一种接口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的. 如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成 AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象。
AIDL RPC机制是通过接口来实现的,类似Windows中的COM或者Corba,但他是轻量级的,客户端和被调用实现之间是通过代理模式实现的,代理类和被代理类实现同一个接口Ibinder接口。
下面是实现Activity访问Service例子的步骤:
一.创建.aidl文件
AIDL使用简单的语法来声明接口,描述其方法以及方法的参数和返回值。这些参数和返回值可以是任何类型,甚至是其他AIDL生成的接口。重要的是必须导入导入除了内建类型(例如:int,boolean等)外的任何其他类型,哪怕是这些类型是在与接口相同的包中。具体的要求如下:
- JAVA基本数据类型不需要导入
- String,List,Map和CharSequence不需要导入
使用Eclipse的ADT插件创建一个BookInfo.aidl文件,该文件有4个方法:
setName(String name)设置图书的书名,setPrice(int price)设置图书的价格,setPublish(String pname)设置图书的出版社和String display()显示图书的信息.
BookInfo.aidl文件
package com.android.aidl; //BookInfo接口 interface BookInfo{ void setName(String name); void setPrice(int price); void ssetPublish(String pname); //显示图书的信息 String display(); }
创建好BookInfo.aidl文件,系统会自动在gen目录下生成Java接口文件BookInfo.java
二.实现AIDL文件生成的JAVA接口
AIDL会生成一个和.aidl文件同名的JAVA接口文件,该接口中有一个静态抽象内部类Stub,该类中声明了AIDL文件中定义的所有方法,其中有一个重要的方法是asInterface(),该方法通过代理模式返回JAVA接口的实现我们可以定义一个实现类,BookImpl,该类继承Stub类,实现我们定义的4个方法
package com.android.aidl; import android.os.RemoteException; public class BookInfoImpl extends BookInfo.Stub { //声明三个个变量 private int price; private String name,pname; //显示书名,价格,出版社 public String display() throws RemoteException{ return "书名:"+name+";价格:"+price+";出版社:"+price; } @Override //设置书名 public void setName(String name) throws RemoteException { // TODO Auto this.name= name; } @Override //设置价格 public void setPrice(int price) throws RemoteException { // TODO Auto-generated method stub this.price = price; } @Override //设置出版社 public void setPublish(String pname) throws RemoteException { // TODO Auto this.pname= pname; } }
三.向客户端暴露接口
现在已经实现了BookInfo接口,接下来要将该接口暴露给客户端调用。一般通过定义一个Service来实现,在Service的onBind()方法中返回该接口,当我们绑定该接口时调用该方法。
package com.android.aidl; import com.android.aidl.BookInfo.Stub; import android.app.Service; import android.content.Intent; import android.os.IBinder; public class RemoteService extends Service { //声明BookInfo接口 private Stub bookifo = new BookInfoImpl(); public IBinder onBind(Intent intent){ return bookifo; } }
四.在客户端调用
定义一个Activity来绑定远程Service,获得BookInfo接口,通过RPC机制调用接口中的方法。
package com.android.aidl; import android.app.Activity; import android.app.Service; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class MainActivity extends Activity { // 声明IPerson接口 private BookInfo bookInfo; // 声明 Button private Button btn; // 实例化ServiceConnection private ServiceConnection conn = new ServiceConnection() { @Override synchronized public void onServiceConnected(ComponentName name, IBinder service) { // 获得IPerson接口 bookInfo = BookInfo.Stub.asInterface(service); if (bookInfo != null) try { // RPC 方法调用 bookInfo.setName("Google Android SDK开发范例大全"); bookInfo.setPrice(55); bookInfo.setPublish("人民邮电出版社"); String msg = bookInfo.display(); // 显示方法调用返回值 Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG) .show(); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 设置当前视图布局 setContentView(R.layout.main); // 实例化Button btn = (Button) findViewById(R.id.Button1); //为Button添加单击事件监听器 btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 实例化Intent Intent intent = new Intent(); // 设置Intent Action 属性 intent.setAction("com.android.aidl.action.MY_REMOTE_SERVICE"); // 绑定服务 bindService(intent, conn, Service.BIND_AUTO_CREATE); } }); } }
五.main.xml和AndroidManifest.xml文件
main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:text="远程调用Service" android:id="@+id/Button1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
在AndroidManifest.xml文件16~20声明Service
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.aidl" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="10" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name="RemoteService"> <intent-filter> <action android:name="com.android.aidl.action.MY_REMOTE_SERVICE"/> </intent-filter> </service> </application> </manifest>
效果图: