Android Studio中使用AIDL进行进程间通信

什么是AIDL

aidl是 Android Interface definition language的缩写,也就是安卓接口定义语言

为什么要有AIDL

AIDL允许你定义客户端与服务端达成一致的程序接口使用进程间通信相互交流。 在Android上面,一个进程不能正常的访问另一个进程的内存。 所以说,他们需要分解他们的对象为操作系统可以理解的基本单位,然后为你把这些对象按次序跨越进程边界 ,书写这些代码是单调冗长的,所以android使用AIDL为你处理这个问题。

注意:使用AIDL只有在你允许来自不同应用的客户端跨进程通信访问你的service,并且想要在你的service种处理多线程的时候才是必要的。 如果你不需要执行不同应用之间的IPC并发,你应该通过实现Binder建立你的接口,或者如果你想执行IPC,但是不需要处理多线程。那么使用Messenger实现你的接口。

如何使用aidl完成进程间通信

1.建立.aidl文件

AIDL使用一个简单的语法让你声明一个带有一个或者多个带有参数和返回值方法的接口 参数和返回值可以是任何类型,甚至是AIDL生成的接口

你必须使用java语言构建.aidl文件 每一个.aidl文件必须定义一个简单的接口并且要求只有接口声明和方法签名

默认的,AIDL支持下面数据类型

ava语言中的所有基本数据类型(比如int、long、char、boolean等等)

  • String
  • CharSequence
  • List

    List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是你定义的parcelable List可以使用范型(例如,List) 接收端的实际类经常是一个ArrayList,尽管方法是使用List接口生成的

  • Map

    Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是你定义的parcelable 范型map是不被支持的(比如这种形式Map) 接收端的实际类经常是一个HashMap,尽管方法是使用Map接口生成的

当定义你的service接口的时候,注意:

  • 方法可以接收0或多个参数,并且有返回值或者返回void
  • 所有非基本数据类型要求要求一个定向的tag来指定数据是去往哪个方向的 无论是输入、输出,还是输入输出(参加下面的例子) 基本数据类型是默认支持的,并且不能是其他的。
  • .aidl文件中的所有的代码注释都在生成的IBinder接口中(除了在import和包声明之前的注释)
  • 只支持方法,你不可以在AIDL暴露静态域

下面给出代码

以Android Stduio为例,我们看看如何使用AIDL进行进程间通信

1.创建IRemoteService .aidl文件

package com.example.aidlserver;

interface IRemoteService {
     int getPid();
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}

但是此时并没有AIDL的java文件产生,其实android studio也是带有自动生成的,只不过需要确认一些信息后才能生成。此时,我们可以在目录 build–>generated–>source–>aidl–>test–>debug下面发现还没有任何文件

此时,打开AndroidManifest.xml,确认package的值,如我这个

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.aidlserver">

关键性的一步,确认aidl文件所在的包名和AndroidMainifest.xml的package名是否一致。如果一致,点击 Build–>Make Project,生成相应的java文件。如果不一致,则改aidl的包名,改成一致,再点击生成,生成效果如图。

我们看看生成的IRemoteService.java的内容

public interface IRemoteService extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.example.aidlserver.IRemoteService {
        private static final java.lang.String DESCRIPTOR = "com.example.aidlserver.IRemoteService";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.example.aidlserver.IRemoteService interface,
         * generating a proxy if needed.
         */
        public static com.example.aidlserver.IRemoteService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.aidlserver.IRemoteService))) {
                return ((com.example.aidlserver.IRemoteService) iin);
            }
            return new com.example.aidlserver.IRemoteService.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_getPid: {
                    data.enforceInterface(DESCRIPTOR);
                    int _result = this.getPid();
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
                case TRANSACTION_basicTypes: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    long _arg1;
                    _arg1 = data.readLong();
                    boolean _arg2;
                    _arg2 = (0 != data.readInt());
                    float _arg3;
                    _arg3 = data.readFloat();
                    double _arg4;
                    _arg4 = data.readDouble();
                    java.lang.String _arg5;
                    _arg5 = data.readString();
                    this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.example.aidlserver.IRemoteService {
            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 int getPid() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) 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.writeInt(anInt);
                    _data.writeLong(aLong);
                    _data.writeInt(((aBoolean) ? (1) : (0)));
                    _data.writeFloat(aFloat);
                    _data.writeDouble(aDouble);
                    _data.writeString(aString);
                    mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    public int getPid() throws android.os.RemoteException;

    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}

我们只看重点部分,这里有一个内部类Stub继承Binder,实现了IRemoteService接口,这个类中有一个方法asInterface,接收一个IBinder对象,并且返回一个IRemoteService类型的对象。

定义远程服务,暴漏接口给客户端

public class RemoteService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
        @Override
        public int getPid() throws RemoteException {
            return Process.myPid();
        }
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }
    };
}

同时,我们需要在清单文件中注册这个服务,并且添加一个action,因为我们是通过远程来调用服务的,所以必须指定一个action,用来隐式启动。

  <service android:name=".RemoteService">
            <intent-filter>
                <action android:name="com.lxn.remote"/>
            </intent-filter>
        </service>

现在,当一个客户端(比如一个activity)调用bindService()来连接到这个service,这个客户端的onServiceConnected()回调函数接收service中onBind()方法返回的mBinder实例

客户端必须可以访问接口类,所以如果客户端和服务端在不同的应用中,那么客户端所在的应用必须有一份.aidl文件的副本,同样,在客户端我们创建一个aidl文件夹,然后把服务器端的aidl文件拷贝到这个目录下,注意:这个时候要保证文件所在的包名和服务器端aidl的包名一样,而不是和当前应用的包名一样,否则会报错。

当客户端在onServiceConnected()回调方法中接收到IBinder时,它必须调用你的ServiceInterface.Stub.asInterface(service)来把返回参数映射到你的ServiceInterface类型上。例如:

  private IRemoteService remoteService;
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            remoteService = IRemoteService.Stub.asInterface(service);
            try {
                int pid = remoteService.getPid();
                int currentPid = Process.myPid();
                System.out.println("currentPid: "+currentPid+", remotePid: "+pid);
                remoteService.basicTypes(1,12,true,3,3,"aa");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            System.out.println("=====bind Success");
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Toast.makeText(MainActivity.this, "service disConneted unexpected", Toast.LENGTH_SHORT).show();
            remoteService = null;
        }
    };

完整代码

服务端:

public class RemoteService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
        @Override
        public int getPid() throws RemoteException {
            System.out.println("=====Thread getPid: "+Thread.currentThread().getName());
            return Process.myPid();
        }
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
            System.out.println("=====Thread basicTypes: "+Thread.currentThread().getName());
        }
    };
}

客户端:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void bindService(View view){
        System.out.println("=====begin bindService");
        Intent service = new Intent("com.lxn.remote");
        //通过bindService绑定服务
        bindService(service,conn,BIND_AUTO_CREATE);
    }
    private IRemoteService remoteService;
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            remoteService = IRemoteService.Stub.asInterface(service);
            try {
                int pid = remoteService.getPid();
                int currentPid = Process.myPid();
                System.out.println("===currentPid: "+currentPid+", remotePid: "+pid);
                remoteService.basicTypes(1,12,true,3,3,"aa");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            System.out.println("=====bind Success");
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Toast.makeText(MainActivity.this, "service disConneted unexpected", Toast.LENGTH_SHORT).show();
            remoteService = null;
        }
    };
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }
}

我们点击客户端的绑定服务按钮,然后在控制台进行结果的输出

那么AIDL是什么原理呢?

AIDL其实通过我们写的aidl文件,帮助我们生成了一个接口,一个Stub类用于服务端,一个Proxy类用于客户端调用。关于详细的细节,我在这里就不讨论了,可以看下面这篇文章:

http://blog.csdn.net/lmj623565791/article/details/38461079

最后给出代码下载位置

点此下载代码

时间: 2024-10-13 07:23:23

Android Studio中使用AIDL进行进程间通信的相关文章

Android IPC机制(三)在Android Studio中使用AIDL实现跨进程方法调用

在上一篇文章Android IPC机制(二)用Messenger进行进程间通信中我们介绍了使用Messenger来进行进程间通信的方法,但是我们能发现Messenger是以串行的方式来处理客户端发来的信息,如果有大量的消息发到服务端,服务端仍然一个一个的处理再响应客户端显然是不合适的.另外,Messenger用来进程间进行数据传递但是却不能满足跨进程的方法调用,接下来我们来使用AIDL来实现跨进程方法调用,此前我们都是用Eclipse来实现的,这次我们看看在Android Studio中使用AI

Android studio 中创建AIDL Service

  1.概述  AIDL在android系统中的作用 AIDL,Android Interface definition language的缩写,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口.最近看了下AIDL在Android系统中的用法,在网上看到很多初学的朋友不太明白AIDL的实际作用,android提供了很多进程间通信的组件,像action.broadcast.contentprovide都可以实现进程间的通信,为什么还要用AIDL这个东西呢?我在a

Android studio 下的aidl编程实现Android的夸进程间通信

前言 Android中夸进程间通信方式有很多种方式,比如:aidl,Messenger,文件共享,广播(BroadCast),ContentProvider,Socket(网络通信).每种方式都有自己的使用场景和优缺点,接下来几篇博客我们一一学习他们是怎么使用的.这篇博客主要是介绍Android studio下实现aidl编程. AIDL的使用步骤 aidl远程调用传递的参数和返回值支持Java的基本类型(int long booen char byte等)和String,List,Map等.当

Android Studio中手动导入Eclipse Project

RT,这应该是很多朋友刚从Eclipse转到Android Studio后遇到最大的一个问题,首先我们需要重新认识AS里面的目录结构,在我前一篇帖子里面也有提到(Android Studio中的Project相当于Eclipse中的Workspace,Module则相当于Eclipse中的Project). 所以我们手动导入Project,其实就是导入AS里面的Module.主要有以下几个步骤: 1.复制build.gradle到需要导入的项目中 2.复制你需要导入的项目至AS Project根

大仙说道之Android studio实现Service AIDL

今天要开发过程中要用到AIDL的调用,之前用的eclipse有大量教程,用起来很方便,现在刚换了Android studio,不可否认studio真的很强大,只是很多功能还需要摸索. AIDL(Android Interface Definition Language)是Android接口定义语言的意思,它可以用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能. 言归正传,今天的主题是远程Service建立AIDL进行通信,通过一

Android Studio实现Service AIDL

Android Studio实现Service AIDL [日期:2015-01-02] 来源:Linux社区  作者:teenyboy [字体:大 中 小] 今天要开发过程中要用到AIDL的调用,之前用的eclipse有大量教程,用起来很方便,现在刚换了Android studio,不可否认studio真的很强大,只是很多功能还需要摸索. AIDL(Android Interface Definition Language)是Android接口定义语言的意思,它可以用于让某个Service与多

在Android studio中如何把项目放到远程git或从远程git得到项目:

主要记录了在Android studio 中如何把项目放到远程git或从远程得到项目: 因为它已经为我们提供了git插件,所有我们部署一下就可以直接使用了.方法如下: 1.准备:先下载window上的git(在不同的系统下载不同的git),然后安装. 2.在Android studio 里点击:File->Settings(如图1),然后进入Version Control->Git;(如图二)然后点击Test(出现图三表示成功). 图1 图二 图三 3.初始化git项目(git init),操

Android Studio 中 FAILURE: Build failed with an exception. * What went wrong: Execution failed for task &#39;:compileDebugAidl&#39;.的问题解答

Android Studio 中 FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':compileDebugAidl'.的问题解答 完整的问题提示 Gradle: FAILURE:Build failed with an exception.*What went wrong:Execution failed for task ':compileDebugAidl'.>No

关于Android Studio中启动模拟器时,报VT-x is disabled in BIOS错误的解决办法

有时候在Android Studio中启动一个模拟器去运行程序的时候,会出现下面的错误提示:"Intel HAXM is required to run this AVD,VT-x is disabled in BIOS". 接下来我来说说解决的办法: 1. 首先在SDK Manager中检查是否安装Download Intel x86 Emulator Accelerator (HAXM installer),如果没有安装,则在SDK Manager中下载安装Download Int