Android进程通信值AIDL

Android进程间通信:

Binder: 只有 IPC(进程间通信)   没有多线程  多个应用程序

Message:只有IPC   没有多线程

AIDL:IPC  多线程  多个应用程序  基于Service实现


AIDL默认支持的数据类型:

基本数据类型(除了short类型外,因为序列化中没有short方法)

String,CharSequence

List,Map

Parcelable

使用

远程调用基本类型数据:

1.AS中创建一个应用,在应用中创建aidl文件夹,然后在文件夹里面创建一个AIDL文件,如图所示:

  

在IExampleAidl.aidl文件会自动生成一个接口和方法,方法可以自己定义,我这里实现两个数的相加

// IExampleAidl.aidl
package com.example.androidaidltest;

// Declare any non-default types here with import statements

interface IExampleAidl {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    int add(int num1,int num2);
}
然后点击AS进行编译,如图:


自定义一个Service类继承Service,实现aidl方法中的接口

public class ExampleService extends Service {


    //客户端绑定该服务的时候就会调用该接口
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    private IBinder binder=new IExampleAidl.Stub(){

        @Override
        public int add(int num1, int num2) throws RemoteException {
            Log.v("test","来自客户端的数据num1="+num1+"     num2="+num2);
            return num1+num2;
        }
    };
}
这里注意,在服务端的manifest清单文件中,要见启动服务更改成自定义的Service
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <service android:name=".ExampleService">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    </service>
</application>

 然后创建一个新的moudle作为客户端,并且将服务端的AIDL文件复制到客户端的对应目录下面,注意,客户端与服务端AIDL的包名必须一致,如图: 

编译客户端的AIDL文件

在客户端调用远程服务:

通过binderService绑定远程服务

private void bindMyService() {
    Intent intent=new Intent();
    intent.setComponent(new ComponentName("com.example.androidaidltest","com.example.androidaidltest.ExampleService"));
    bindService(intent,conn, Context.BIND_AUTO_CREATE);
}
ServiceConnection中通过 asInterface方法 获取远程服务的代理

ServiceConnection conn=new ServiceConnection() {
    //绑定上服务的时候
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        //获取远程服务,此处为远程服务的代理Proxy
        myAidl= IExampleAidl.Stub.asInterface(iBinder);

    }

    //断开的时候
    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        //回收资源
        myAidl=null;
    }
};
获取远程服务对象之后,就可以调用其中的方法了,先运行服务端,再运行客户端,服务端没有界面。

具体实现参见链接中的demo:

http://download.csdn.net/detail/luck_136/9606080

远程调用自定义对象:

自定义javaBean对象,实现Parcelable接口,并实现对应的方法,同时还要实现Creator<T>静态接口,eg:

public static final Creator<Persion> CREATOR=new Creator<Persion>() {
    @Override
    public Persion createFromParcel(Parcel parcel) {
        return new Persion(parcel);
    }

    @Override
    public Persion[] newArray(int i) {
        return new Persion[i];
    }
};
在AIDL文件中添加对应的JavaBean的AIDL文件,这里以Persion为例,该 Persion.aidl文件中的内容为:

// IPersion.aidl
package com.example.aidlpersion;

// Declare any non-default types here with import statements

import com.example.aidlpersion;

parcelable Persion;
然后在原来的AIDL文件中使用Persion,这里要注意导入Persion的包,如图


IPersion.aidl中的内容为:

// IPersion.aidl
package com.example.aidlpersion;

// Declare any non-default types here with import statements

import com.example.aidlpersion.Persion;

interface IPersion {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    List<Persion> add(in Persion p);
}
这里的“in” 表示输入

然后对服务器端进行编译,其他处理跟传递基础类型数据是一样的,另外也要讲自定义的对象复制到客户端,并且包名也要跟服务端一致

具体实现见以下链接中的demo:

http://download.csdn.net/detail/luck_136/9606084


AIDL原理简单解析:

首先来看如下图示:



通过图示我们可以看到服务端初始化了内部类Stub,客户端通过asInterface获取远程服务的代理Proxy,而功能的实现是通过transact调用,transact又调用了onTransact.下面看看里面的代码逻辑。我们将.aidl文件进行编译会在build——>generated——>source——>aidl——>debug目录下生成对应的java文件,如下图所示:


我们来看看java文件IPersion中的代码


我们看到整个文件就是跟我们定义的aidl文件是一致的,只是多了一个Stub的抽象存根类,那么下面看看Stub里面有做了什么:

/** 存根抽象类类*/
public static abstract class Stub extends android.os.Binder implements com.example.aidlpersion.IPersion
{
private static final java.lang.String DESCRIPTOR = "com.example.aidlpersion.IPersion";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.example.aidlpersion.IPersion interface,
 * generating a proxy if needed.
 */
public static com.example.aidlpersion.IPersion asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.aidlpersion.IPersion))) {
return ((com.example.aidlpersion.IPersion)iin);
}
return new com.example.aidlpersion.IPersion.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_add:
{
data.enforceInterface(DESCRIPTOR);
com.example.aidlpersion.Persion _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.aidlpersion.Persion.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
java.util.List<com.example.aidlpersion.Persion> _result = this.add(_arg0);
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}



private static class Proxy implements com.example.aidlpersion.IPersion
{
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;
}
/**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
@Override public java.util.List<com.example.aidlpersion.Persion> add(com.example.aidlpersion.Persion p) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.aidlpersion.Persion> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((p!=null)) {
_data.writeInt(1);
p.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.aidlpersion.Persion.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}




static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}

先看Stub类中asInterface方法

/**
 * Cast an IBinder object into an com.example.aidlpersion.IPersion interface,
 * generating a proxy if needed.
 */
public static com.example.aidlpersion.IPersion asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.aidlpersion.IPersion))) {
return ((com.example.aidlpersion.IPersion)iin);
}
return new com.example.aidlpersion.IPersion.Stub.Proxy(obj);
}
可以看到asInterface返回一个IPersion的对象,但是其内部是通过Proxy拿到的IPersion对象

再看看内部类Proxy

private static class Proxy implements com.example.aidlpersion.IPersion
{
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;
}
/**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
@Override public java.util.List<com.example.aidlpersion.Persion> add(com.example.aidlpersion.Persion p) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.aidlpersion.Persion> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((p!=null)) {
_data.writeInt(1);
p.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.aidlpersion.Persion.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
可以看到Proxy内部调用了 mRemote .transact( Stub. TRANSACTION_add , _data, _reply, 0 )方法

而我们可以看到在Stub类中有一个onTransact()方法

@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_add:
{
data.enforceInterface(DESCRIPTOR);
com.example.aidlpersion.Persion _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.aidlpersion.Persion.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
java.util.List<com.example.aidlpersion.Persion> _result = this.add(_arg0);
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
可以看到在onTransact通过code来进行判断,之前调用 transact方法的时候我们是传入了一个Stub.TRANSACTION_add的值,这个值就是一个code,在Stub中定义了,当code值为TRANSACTION_add,在远程的方法中做相关的操作。

至此,利用AIDL完成进程间通信的过程就分析完成了,主要就是用到了代理模式,利用Server的IBinder完成的。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中的AIDLAndroid Interface Definition Language)是一种用于进程间通信的机制,它允许在不同进程中的组件之间进行通信AIDL是一个基于接口的编程语言,它定义了一组方法,这些方法可以被其他进程中的组件调用。 AIDL的使用步骤如下: 1.定义AIDL接口:定义接口和方法,并在方法中指定参数和返回类型。 2.实现AIDL接口:实现AIDL接口中定义的方法。 3.注册AIDL服务:在AndroidManifest.xml文件中注册服务。 4.使用AIDL服务:获取AIDL对象并调用方法。 下面是一个简单的例子,演示如何使用AIDL进行进程间通信。 1.定义AIDL接口 ``` interface IMyAidlInterface { void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); } ``` 2.实现AIDL接口 ``` public class MyAidlService extends Service { private static final String TAG = "MyAidlService"; private IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { Log.d(TAG, "basicTypes: " + anInt + ", " + aLong + ", " + aBoolean + ", " + aFloat + ", " + aDouble + ", " + aString); } }; @Nullable @Override public IBinder onBind(Intent intent) { return mBinder; } } ``` 3.注册AIDL服务 在AndroidManifest.xml文件中添加以下代码: ``` <service android:name=".MyAidlService" android:exported="true"> <intent-filter> <action android:name="com.example.MyAidlService" /> </intent-filter> </service> ``` 4.使用AIDL服务 ``` public class MainActivity extends AppCompatActivity { private IMyAidlInterface mService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(); intent.setAction("com.example.MyAidlService"); intent.setPackage("com.example"); bindService(intent, mConnection, BIND_AUTO_CREATE); } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { mService = IMyAidlInterface.Stub.asInterface(iBinder); try { mService.basicTypes(1, 2L, true, 3.0f, 4.0, "Hello, AIDL!"); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName componentName) { mService = null; } }; } ``` 在上面的代码中,我们首先创建一个Intent对象,指定要绑定的服务的包名和类名。然后调用bindService()方法绑定服务,并在onServiceConnected()方法中获取AIDL对象,调用basicTypes()方法向服务传递参数。最后,在onServiceDisconnected()方法中释放AIDL对象。 以上就是使用AIDL进行进程间通信的基本步骤。需要注意的是,在使用AIDL时,必须确保服务已经启动,并且在AndroidManifest.xml文件中注册了服务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值