AIDL实现Android进程间的通信

今天来详讲一种Android进程通信的方式:AIDL

AIDL:android接口定义语言

AIDL的作用:首先我们知道,每个进程都运行在自己的虚拟机中,拥有自己独立的内存地址空间,在自己的内存空间操作自己的数据,但如果想跟其它内存空间通信时。这时就涉及到进程之间的通信,aidl就是它们通信的桥梁之一,它制定自己的规则,只要按照它的规则来就可以实现进程之间的通信。

为什么选用AIDL来进行进程之间的通信:

(1)Messenger时串行方式处理客户端发来的消息,如果有大量消息同时发送到服务端,Messenger只能一条一条道处理。但是如果有大量并发请求,那么Messenger就不行了。另外Messenger主要是传送消息用的,如果我们想调用服务端的方法时,这个时候就要AIDL 了。

(2)BroadcastReceive也可以进行进程之间的通信,但是BroadcastReceive占用的系统资源太多,显然如果频繁的调用的话是不合适的。

AIDL所能使用的数据类型:

(1)  java八种基本类型:int ,short , long , byte , char , Boolean , float ,double .

(2)  List的ArrayList.

(3)  Map的HashMap

(4)  实现了parcelable的对象

(5)   CharSequence、string类型。

定向tag:分别有in、out、inout。这里选择的参考对象是服务端。In表示数据只能从客户端流向服务端。Out表示数据只能从服务端流向客户端。Inout可以双向流动,inout使用比较消耗系统资源。

下面跟着例子讲一下AIDL通信原理:

项目结构:


1、新建一个aidl文件:IBookManager.aidl

// IBookManager.aidl
package com.ryg.ipcaidl;
import com.ryg.ipcaidl.Book;//因为下面用到Book这个类,所以这里一定要import Book。
interface IBookManager {
    List<Book> getBookList();//因为这里用到Book这个类,所以一定要新建一个Book.aidl文件
    void addBook(in Book book);
}


2、Book.aidl

package com.ryg.ipcaidl;

parcelable Book;

3、此时ReBuild一下,这时那会发现工程下多了一个IBookManager.java的接口文件


在这里来个一个小插曲:

有可能那在rebuild的时候,会报以下错误:



解决办法有两个:

(1)修改 build.gradle 文件:在 android{} 中间加上下面的内容:

buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

(2)或者将你写的Book.java文件放在项目的包路径下。

 

4、这里来详细解说一下IBookManager.java这个文件:

其实这个时候可以将之前的aidl文件删除,它的作用已经用完,哈哈。

默认生成的BookManagerImpl.java文件是这样的:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: /Users/apple/workSpace/IPCAidl/app/src/main/aidl/com/ryg/ipcaidl/IBookManager.aidl
 */
package com.ryg.ipcaidl;
public interface IBookManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.ryg.ipcaidl.IBookManager
{
private static final java.lang.String DESCRIPTOR = "com.ryg.ipcaidl.IBookManager";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.ryg.ipcaidl.IBookManager interface,
 * generating a proxy if needed.
 */
public static com.ryg.ipcaidl.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.ryg.ipcaidl.IBookManager))) {
return ((com.ryg.ipcaidl.IBookManager)iin);
}
return new com.ryg.ipcaidl.IBookManager.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_getBookList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.ryg.ipcaidl.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(DESCRIPTOR);
com.ryg.ipcaidl.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.ryg.ipcaidl.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.ryg.ipcaidl.IBookManager
{
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 java.util.List<com.ryg.ipcaidl.Book> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.ryg.ipcaidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.ryg.ipcaidl.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.ryg.ipcaidl.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.util.List<com.ryg.ipcaidl.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.ryg.ipcaidl.Book book) throws android.os.RemoteException;
}


我们可以把这里面的代码整理一下,便于分析(重点:分析过程已经在代码的注释里面说明,请大家仔细阅读):

package com.ryg.ipcaidl;

import android.media.audiofx.AudioEffect;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;

import java.util.List;

import static com.ryg.ipcaidl.IBookManager.Stub.DESCRIPTOR;
import static com.ryg.ipcaidl.IBookManager.Stub.TRANSACTION_getBookList;

/**
 * Created by apple on 17/5/7.
 */

public interface IBookManager extends IInterface{
    //创建一个接口对象Stub
    public static abstract class Stub extends Binder implements IBookManager{
        public Stub(){
            this.attachInterface(this, DESCRIPTOR);
        }

        //这个方法运行在服务端的binder线程池中,将服务端的binder方法转化为客户端所能识别的aidl接口
        public static IBookManager asInterface(IBinder obj){
            if (obj == null){
                return null;
            }
            return new IBookManager.Stub().Proxy(obj);
        }

        //用于返回当前的binder对象
        @Override
        public IBinder asBinder() {
            return this;
        }


        //该方法运行在 客户端
        private static class Proxy implements IBookManager{
            private Binder mRemote;
            Proxy(IBinder remote){

            }
            @Override
            public List<Book> getBookList() throws RemoteException {
                //创建输入型Parcel对象
                Parcel data = Parcel.obtain();
                //创建输出型Parcel对象
                Parcel reply = Parcel.obtain();
                List<Book> result;
                //把参数信息写入data中
                data.writeInterfaceToken(DESCRIPTOR);

                //调用transact方法发起远程请求,客户端当前线程挂起,服务端此时调用onTransact方法
                mRemote.transact(TRANSACTION_getBookList,data,reply,0);

                //获取rpc过程中的返回值
                reply.readException();
                result = reply.createTypedArrayList(Book.CREATOR);

                //并将该返回值返回,当前线程继续执行
                return result;
            }

            @Override
            public void addBook(Book book) throws RemoteException {

            }

            @Override
            public IBinder asBinder() {
                return null;
            }
        }




        //这个方法运行在 服务端 的binder线程池中,当客户端发起远程请求时,会将远程请求通过系统底层封装后,交由此方法处理
        //这个方法有四个参数。code:客户端请求的目标方法是什么。data:取出目标方法所需要的参数。repl:执行完毕以后向reply中写数据
        //注意这个方法返回的是boolean类型,如果这个方法返回的是fals,说明此客户端没有权限访问这个服务端
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            return super.onTransact(code, data, reply, flags);
        }

        //具体方法
        @Override
        public List<Book> getBookList() throws RemoteException {
            return null;
        }
        //具体方法
        @Override
        public void addBook(Book book) throws RemoteException {

        }

    }





}



 

5、原理看完以后继续,看我们实际当中怎么使用它,在本实例中客户端代码如下:

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import java.util.List;

public class BookClientActivity extends AppCompatActivity {
    private static final String TAG = "BookClientActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //启动服务端
        Intent intent = new Intent();
        intent.setAction("com.ryg.ipcaidl.launch");
        intent.setPackage(getPackageName());
        bindService(intent,mConnection, Context.BIND_AUTO_CREATE);

    }

    //获得与服务端链接
    private ServiceConnection mConnection =
            new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    //调用运行在服务端的asinterface()方法
                    //将服务端的binder对象转化为客户端所需要的aidl接口对象
                    IBookManager bookManager = IBookManager.Stub.asInterface(service);
                    try {
                        //直接调用服务端方法
                        List<Book> list = bookManager.getBookList();
                        Log.e(TAG,"获取所有书的list :"+list.toString());

                        Book newBook  = new Book(3,"客户端添加的书3");
                        bookManager.addBook(newBook);

                        list = bookManager.getBookList();
                        Log.e(TAG,"客户端添加以后 获取所有书的list :"+list.toString());

                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }

                }

                @Override
                public void onServiceDisconnected(ComponentName name) {

                }
            };

    @Override
    protected void onDestroy() {
        unbindService(mConnection);
        super.onDestroy();
    }
}
客户端使用IMessenger.Stub.asInterface(target)拿到接口实例进行调用


6、服务端代码如下:

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created by apple on 17/5/7.
 */

public class BookManagerService extends Service{
    private static final String TAG = "BookManagerService";

    //用CopyOnWriteArrayList创建一个线程同步的对象
    private CopyOnWriteArrayList<Book> mBookList =
            new CopyOnWriteArrayList<Book>();

    //创建一个binder对象
    private Binder mBinder = new IBookManager.Stub(){

        @Override
        public List<Book> getBookList() throws RemoteException {
            return mBookList;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            mBookList.add(book);
        }


    };

    @Override
    public void onCreate() {
        super.onCreate();
        mBookList.add(new Book(1,"服务端添加的书1"));
        mBookList.add(new Book(2,"服务端添加的书2"));


    }

    //返回这个binder对象
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

服务端OnBind利用stub编写接口实现返回


7、 实现了parcelable的对象

package com.ryg.ipcaidl;

import android.os.Parcel;
import android.os.Parcelable;

public class Book implements Parcelable {

    public int bookId;
    public String bookName;

    public Book() {

    }

    public Book(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(bookId);
        out.writeString(bookName);
    }

    public static final Creator<Book> CREATOR = new Creator<Book>() {
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    private Book(Parcel in) {
        bookId = in.readInt();
        bookName = in.readString();
    }

    @Override
    public String toString() {
        return String.format("[bookId:%s, bookName:%s]", bookId, bookName);
    }

}


 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值