使用Android接口描述语言(AIDL)

AIDL简介

Andorid提供了一种轻量级的进程间通信机制:接口描述语言(Android Interface Definition Language),简称AIDL。进程间使用AIDL通信跟使用Intent通信的最大区别在于:前者是同步通信,而后者是异步通信。AIDL的语法与JAVA中的Interface十分相似,对数据类型的支持方面有一些差别,目前AIDL支持的数据类型有:

使用AIDL的步骤

  1. 创建.aidl文件,在文件中声明远程服务的接口
  2. 在.java文件中实现.aidl中声明的方法
  3. 在AndroidMainifest中注册上面创建的服务
  4. 客户端请求绑定服务成功后就可以调用.aidl中声明的方法了

示例解析

项目目录结构: alt none

  1. 在项目src文件夹下创建IAddService.aidl文件,在aidl声明了一个addOne方法,这个方法简单的把传入的值加上一。

    IAddService.aidl:

    package net.lnmcc.aidltest.aidl;
       
    interface IAddOneService {
    	int addOne(int value);
    }
    

    保存.aidl文件后,Eclipse将会自动在gen/文件夹下生成一个IAddService.java文件,在后面实现远程服务的时候会使用到其中的抽象类Stub。

  2. 创建AddService,AddService是一个bound服务,需要实现onBind()方法,它将返回一个IAddService.Stub实例。IBinder简单的理解成进程间通信的通道,可以通过这个通道来实现数据传输。

    AddService.java:

    public class AddService extends Service {
       
    	IAddService.Stub mBinder;
       
    	@Override
    	public void onCreate() {
    		super.onCreate();
    		mBinder = new IAddService.Stub() {
       
                           //简单的把参数加 1
    			@Override
    	       		public addOne(int value) throws RemoteException {
    				return value + 1;
    			}
    		};
    	}
       
            //当客户端请求绑定服务成功后,会调用这个方法,并把mBinder返回, 
            //mBinder引用了一个IAddService.Stub实例,从而使得客户端可以   
            //成功调用IAddService.Stub中的方法,于是mBinder成了一个通信通道
            @Override
    	public IBinder onBind(Intent arg0) {
    		return mBinder;
    	}
       
    	@Override
    	public void onDestroy() {
    		super.onDestroy();
    	}
    }
    

    接下来需要在AndroidManifest.xml中声明service:

    <service android:name="net.lnmcc.aidltest.AddService" android:process="net.lnmcc.aidltest.AddService" />
    
    需要说明的是android:process指示把这个service当做一个独立的进程来执行,进程名字即”net.lnmcc.aidltest.AddService”。之所以这么做是因为我们是在一个app中演示进程间通信。当运行本例子的时候,使用ps grep aidl命令可以看到有2个进程。但在一般情况下,service和client分属于2个app,自然属于两个不同进程,并不需要声明android:process 。
  3. 创建client端,连接IAddService,连接成功后就可以像调用本地方法一样调用远程方法(这里称AIDL中声明的方法为远程方法)。

    public class AddClient extends Activity {
       
    	IAddService service;
       
            //myServiceConnection用来管理服务连接,      
            //服务连接成功后会调用onServiceConnected方法,
            //断开连接时会调用onServiceDisconnected方法  
       
    	myServiceConnection connection;
       
    	class myServiceConnection implements ServiceConnection {
       
                    //服务连接成功时调用,                          
                    //IAddService.Stub.asInterface()是一个辅助方法,
                    //可以把IBinder类型的变量转换成IAddService类型   
                    @Override
    		public void onServiceConnected(ComponentName name, IBinder boundservice) {
       
    			service = IAddService.Stub.asInterface(boundservice);
    			Toast.makeText(AddClient.this, "Service connected", Toast.LENGTH_SHORT).show();
    		}
       
    		@Override
    		public void onServiceDisconnected(ComponentName name) {
    			service = null;
    			Toast.makeText(AddClient.this, "Service disconnected", Toast.LENGTH_SHORT).show();
    		}
    	}
       
    	private  void initService() {
    		connection = new myServiceConnection();
       
                    //创建一个action intent, 用来连接到远程服务。       
                    //服务名字必须跟前面在AndroidManifest.xml中注册的一样
       
    		Intent i = new Intent();
    		i.setClassName("net.lnmcc.aidltest", net.lnmcc.aidltest.AddService.class.getName());
       
                    //请求绑定到Intent指定的远程服务                   
                    //第二个参数是用来具体处理连接的ServiceConnection对象
                    //BIND_AUTO_CREATE标志表示如果服务不存在,则自动启动 
       
    		if(!bindService(i, connection, Context.BIND_AUTO_CREATE)) {
    			Toast.makeText(AddClient.this, "Bind Service Failed", Toast.LENGTH_SHORT).show();
    		}
    	}
       
    	private void releaseService() {
    		unbindService(connection);
    		connection = null;
    	}
       
    	private TextView result; 
    	private EditText value;
            private Button btnAdd; 
       
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
       
                    //这是app的主activity,布局中包括了一个用于输入值的EditText
                    //一个显示结果的TextView和一个提交按钮                   
       
    	        setContentView(R.layout.activity_main);		
       
                    result = (TextView)findViewById(R.id.result);
    	        value = (EditText)findViewById(R.id.value);
                    initService();
       
    		btnAdd = (Button)findViewById(R.id.addone);
    		btnAdd.setOnClickListener(new View.OnClickListener() {
       
    			@Override
    			public void onClick(View v) {
    				int v1, res = 0;
    				try{
    					v1 = Integer.parseInt(value.getText().toString());
    					res = service.addOne(v1);
    				}catch(RemoteException e) {
    					e.printStackTrace();
    				}
    				result.setText(Integer.valueOf(res).toString());
    			}
    		});
    	}
       
    	@Override
    	protected void onDestroy() {
    		releaseService();
    		super.onDestroy();
    	}
    }
    
    1. AndroidManifest.xml:

        <application
              android:allowBackup="true"
              android:icon="@drawable/ic_launcher"
              android:label="@string/app_name"
              android:theme="@style/AppTheme" >
              <activity
                  android:name="net.lnmcc.aidltest.AddClient"
                  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="net.lnmcc.aidltest.AddService" android:process="net.lnmcc.aidltest.AddService" />
          </application>
      

      5.activity_main.xml:

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical"
          android:text="Android AIDL"
          android:textSize="22dp" >
            
          <LinearLayout
              android:orientation="horizontal"
              android:layout_width="fill_parent"
              android:layout_height="wrap_content">
            
              <EditText 
                  android:id="@+id/value"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"/>
            
              <Button 
                  android:id="@+id/addone" 
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:text="+1" />
          </LinearLayout>
            
          <TextView
              android:id="@+id/result"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="result" />
            
      </LinearLayout>
      

git clone https://github.com/lnmcc/AIDLTest.git