Android AIDL的原理和使用

一、什么是AIDL

AIDL,全称Android Interface definition language,是Android中IPC(Inter-Process Communication)进程通信方式的一种。

说到进程通信,就要区分一下什么是进程什么是线程:

进程一般指的是一个执行单元,它拥有独立的地址空间,也就是一个应用或者一个程序。

线程是CPU调度的最小单元,是进程中的一个执行部分或者说是执行体,两者之间是包含与被包含的关系。

 

AIDL的作用:生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数,来完成进程间通信。

 

二、使用和原理

AIDL的实现可分为三部分:

1、客户端,调用远程服务。

2、服务端,提供服务。

3、AIDL接口,用来传递的参数,提供进程间通信。

Demo:

创建自定义类Book,实现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 getBookId() {
        return bookId;
    }

    public void setBookId(int bookId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.bookId);
        dest.writeString(this.bookName);
    }

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

    public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel source) {
            return new Book(source);
        }

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

新建一个IBookManager.aidl文件

import com.kwmax.aidldemo.Book;

interface IBookManager {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    void addBook(in Book book);
    List<Book> getBookList();
}

默认格式是basicType方法中的几种,addBook,getBook为我们添加的方法。

注意在AIDL中,Book需要import导入:import com.kwmax.aidldemo.Book;

此外,自定义的Parcelable对象,必须创建一个和它同名的AIDL文件,并在其中声明它为parcelable类型。

// Book.aidl
package com.kwmax.aidldemo;
 
parcelable Book;

以上完成之后,make project,AS会为我们自动为我们生成对应的Binder类:IBookManager,

路径在build->generated->source->aidl文件夹下

该接口中有个重要的内部类Stub ,继承了Binder 类,同时实现了IBookManager接口

public static abstract class Stub extends android.os.Binder implements com.kwmax.aidldemo.IBookManager

在内部类Stub中,有几个常量和方法需要注意一下:

TRANSACTION_basicTypes、TRANSACTION_addBook、TRANSACTION_getBookList是几个方法的标识id

DESCRIPTOR常量是 Binder的唯一标识,一般用当前Binder的类名表示

asInterface 方法:用于将服务端的Binder对象转换为客户端所需要的接口对象,该过程区分进程,如果进程一样,就返回服务端Stub对象本身,否则呢就返回封装后的Stub.Proxy对象。

onTransact 方法:运行在服务端的Binder线程中的,当客户端发起远程请求后,在底层封装后会交由此方法来处理。通过code来区分客户端请求的方法,注意一点的是,如果该方法返回false,客户端的请求就会失败。一般可以用来做权限控制。

Proxy:代理类。在代理类中,有两个方法,我们定义的addBook和getBookList方法。

@Override public void addBook(com.lvr.aidldemo.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();
}
}

两个方法都是运行在客户端,当客户端发起远程请求时,_data会写入参数,然后调用transact方法发起RPC(远程过程调用)请求,同时挂起当前线程。服务端的onTransact方法就会被 调起,直到RPC过程返回后,当前线程继续执行,并从_reply取出返回值(如果有的话),并返回结果。

接下来,让客户端和服务端实现调用

实现进程间通信可以在同个应用中也可以不在一个应用中。这里我们在同个应用中,创建clientActivity在默认进程中,创建service在remote进程中。

在AndroidManifest注册service:

    <service
            android:name=".ServerService"
            android:process=":remote">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
                <action android:name="com.kwmax.aidldemo.ServerService"/>
            </intent-filter>
    </service>

客户端:绑定service -> 将服务端返回的Binder对象转换成AIDL接口所属的类型 -> 调用AIDL中的方法

public class ClientActivity extends AppCompatActivity implements View.OnClickListener{
    private Button mBinderButton;
    private Button mAddButton;
    private IBookManager mIBookManager;
    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            //通过服务端onBind方法返回的binder对象得到IBookManager的实例,得到实例就可以调用它的方法了
            mIBookManager = IBookManager.Stub.asInterface(binder);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mIBookManager = null;
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mBinderButton = (Button) findViewById(R.id.bindService);
        mAddButton = (Button) findViewById(R.id.addBook);
        mBinderButton.setOnClickListener(this);
        mAddButton.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.bindService:{
                Intent intentService = new Intent();
                intentService.setAction("com.kwmax.aidldemo.ServerService");
                intentService.setPackage(getPackageName());
                intentService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                ClientActivity.this.bindService(intentService, mServiceConnection, BIND_AUTO_CREATE);
                Toast.makeText(getApplicationContext(),"绑定服务!!",Toast.LENGTH_SHORT).show();

                break;
            }
            case R.id.addBook:{
                if(mIBookManager!=null){
                    try {
                        mIBookManager.addBook(new Book(18,"新添加的书"));
                        //获取执行结果
                        Toast.makeText(getApplicationContext(),mIBookManager.getBookList().size()+"",Toast.LENGTH_SHORT).show();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }

                break;
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mIBookManager!=null){
            unbindService(mServiceConnection);
        }
    }
}

服务端:实现Stub 类,并定义接口中方法的具体实现

public class ServerService extends Service {
    private List<Book> mBookList = new ArrayList<>();
    //实现了AIDL的抽象函数
    private IBookManager.Stub mbinder = new IBookManager.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
            //什么也不做
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            //添加书本
            if(!mBookList.contains(book)){
                mBookList.add(book);
            }
        }

        @Override
        public List<Book> getBookList() throws RemoteException {
            return mBookList;
        }
    };
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mbinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        for (int i = 1; i < 6; i++) {
            Book book = new Book();
            book.bookName = "book#" + i;
            book.bookId = i;
            mBookList.add(book);
        }
    }
}

当客户端连接服务端,服务端就会调用onBind方法,把Stub实现对象返回给客户端,该对象是个Binder对象,可以实现进程间通信。

至此,AIDL部分基本弄明白了,至于内部Binder机制是怎么实现通信的,请听下回分解吧~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KWMax

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值