现在的位置: 首页 > 综合 > 正文

Android进程间通信 — AIDL

2017年12月15日 ⁄ 综合 ⁄ 共 7010字 ⁄ 字号 评论关闭

一、前言

Android中的RPC参考了JAVA中的RMI(remote methord invocation)方案;Android中的RPC机制是为了实现进程间通信,即一个进程使用另一个进程中的远程对象,Android用AIDL(android interface defined language,Android接口定义语言)来实现,使用户可以很方便的定义一套接口,然后通过远程Service为代理,客户端在绑定该远程Service时,获得远程对象,然后就可以使用该对象。

二、流程

1. 定义一个.aidl接口文件,ADT则会在gen目录下,自动生成一个对应的.java文件(此文件为自动生成,不可修改);
2. 自动生成的.java中,有一个抽象的Stub类,因此,创建一个基于Stub的子类,并实现在.aidl中定义的接口;
3. 创建一个Service子类,在onCreate中,创建步骤2中的实例对象,在onBind中,返回该实例对象;
4. 在Activity中,发送一个bindService(it, conn, BIND_AUTO_CREATE),请求绑定远程Service;
5. 若成功,则在ServiceConnection.onServiceConnected中获得步骤3中的实例对象;
6. 在AndroidManifest.xml中,注册远程Service;

三、例子

按照流程中的步骤,实现该例子:

3.1 定义.aidl文件

package com.chris.rpc.aidl;

interface ITest {
	void setCustomerName(String name);
	String getCustomerName();
}

很简单,定义了两个接口,然后,ADT就会自动在gen目录下生成ITest.java文件,我们来看看:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: E:\\chris\\Android_Dev\\eclipse\\workspace\\RpcAidl\\src\\com\\chris\\rpc\\aidl\\ITest.aidl
 */
package com.chris.rpc.aidl;
public interface ITest extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.chris.rpc.aidl.ITest
{
private static final java.lang.String DESCRIPTOR = "com.chris.rpc.aidl.ITest";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.chris.rpc.aidl.ITest interface,
 * generating a proxy if needed.
 */
public static com.chris.rpc.aidl.ITest asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.chris.rpc.aidl.ITest))) {
return ((com.chris.rpc.aidl.ITest)iin);
}
return new com.chris.rpc.aidl.ITest.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_setCustomerName:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
this.setCustomerName(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getCustomerName:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getCustomerName();
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.chris.rpc.aidl.ITest
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public void setCustomerName(java.lang.String name) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(name);
mRemote.transact(Stub.TRANSACTION_setCustomerName, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public java.lang.String getCustomerName() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getCustomerName, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_setCustomerName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getCustomerName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public void setCustomerName(java.lang.String name) throws android.os.RemoteException;
public java.lang.String getCustomerName() throws android.os.RemoteException;
}

3.2 创建Stub子类,并实现接口:

package com.chris.rpc.aidl;

import android.os.RemoteException;
import android.util.Log;

import com.chris.rpc.aidl.ITest.Stub;

public class MyTest extends Stub {

	private final static String TAG = "ChrisRpcAidl";
	private String strName = "";
	@Override
	public void setCustomerName(String name) throws RemoteException {
		Log.d(TAG, "[MyTest] setCustomerName name = " + name);
		strName = name;
	}

	@Override
	public String getCustomerName() throws RemoteException {
		Log.d(TAG, "[MyTest] getCustomerName name = " + strName);
		return strName;
	}

}

3.3 创建远程Service类:

package com.chris.rpc.aidl;

import com.chris.rpc.aidl.ITest.Stub;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {

	private final static String TAG = "ChrisRpcAidl";
	private Stub mTest = null;
	@Override
	public IBinder onBind(Intent arg0) {
		Log.d(TAG, "onBind ...");
		return mTest;
	}
	@Override
	public void onCreate() {
		Log.d(TAG, "onCreate ...");
		mTest = new MyTest();
		super.onCreate();
	}

}

3.4 在Activity中请求绑定该远程Service,并获取实例:

package com.chris.rpc.aidl;

import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;

public class MainActivity extends Activity {

	private final static String TAG = "ChrisRpcAidl";
	private final static String SERVICE_ACTION = "com.chris.rpc.aidl.action.MYSERVICE";
	private ITest mTest = null;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		Intent it = new Intent();
		it.setAction(SERVICE_ACTION);
		// 发送绑定Service请求,如果成功,则会调用ServiceConnection
		bindService(it, conn, BIND_AUTO_CREATE);
	}
	
	private ServiceConnection conn = new ServiceConnection(){
		// 绑定成功,返回的对象是IBinder接口,通过asInterface转换为定义的ITest接口
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			Log.d(TAG, "onServiceConnected ...");
			
			mTest = ITest.Stub.asInterface(service);
			if(mTest != null){
				try {
					mTest.setCustomerName("chris");
					Log.d(TAG, "-------------------");
					Log.d(TAG, "get name = " + mTest.getCustomerName());
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			
		}
	};
}

3.5 在AndroidManifest.xml中,注册远程Service:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.chris.rpc.aidl"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="10"
        android:targetSdkVersion="10" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.chris.rpc.aidl.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="com.chris.rpc.aidl.MyService">
            <intent-filter>
                <action android:name="com.chris.rpc.aidl.action.MYSERVICE" />
            </intent-filter>
        </service>
    </application>

</manifest>

3.6 运行截图:

四、小结

本篇文章是让大家了解AIDL的过程,特别是大家需要理解一个自动生成的接口类的中Stub, asInterface, onTransact方法,这些方法在Android Java Framework中有对应的实现,并最终通过native来完成。然后就是大家要了解这个远程Service的用法就可以了。AIDL通常用在如手机播放器这类应用中,各个activity与service绑定后,可以控制播放器的各个状态。
(之后要是有空,我会继续写androd java framework中关于binder的理解)

抱歉!评论已关闭.