安卓进程通讯之aidl

来源:互联网 发布:淘宝与京东 编辑:程序博客网 时间:2024/06/05 11:32

安卓进程通讯之aidl

通过bindservice可以启动远程service并在onServiceConnected拿到远程service传来的 IBinder,但是如何把IBinder转换成对应的接口类型呢?这里就要使用aidl。
这里以图书管理为例讲解aidl。
首先,确定远程service需要提供的功能。
1,获取图书列表;
2,往图书列表中加入一本书;
3,注册新书到货的观察者;
4,注销新书到货观察者;

先声明 Book实体类,这里注意,跨进程传输的对象必须实现parcel接口

public class Book implements Parcelable{private int id;private String name;    @Overridepublic String toString() {    return "Book [id=" + id + ", name=" + name + "]";}    public int getId() {    return id;}public void setId(int id) {    this.id = id;}public String getName() {    return name;}public void setName(String name) {    this.name = name;}    public Book(int id, String name) {    super();    this.id = id;    this.name = name;}    @Override    public int describeContents() {        // TODO Auto-generated method stub        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeInt(id);        dest.writeString(name);    }public static final Parcelable.Creator<Book> CREATOR=new Creator<Book>() {    @Override    public Book[] newArray(int size) {        // TODO Auto-generated method stub        return new Book[size];    }    @Override    public Book createFromParcel(Parcel source) {        // TODO Auto-generated method stub        return new Book(source);    }};private Book(Parcel parcel){    this.id=parcel.readInt();    this.name=parcel.readString();}}

同时创建文件Book.aidl声明Book类是parcelable

package com.example.aidlbookmanager;parcelable Book;

监听新书回调接口OnNewBookListener
该不能是普通java接口,需要是aidl接口才可以。
创建OnNewBookListener.aidl文件,文件内容如下

package com.example.aidlbookmanager;import com.example.aidlbookmanager.Book;interface OnNewBookListener{void onNewBook(in Book book);}

这里需要引入Book包,在onNewBook方法里的in表示方向,对远程service而言是从客户端传入的.

创建IBookManager.aidl文件,内容如下

package com.example.aidlbookmanager;import com.example.aidlbookmanager.Book;import com.example.aidlbookmanager.OnNewBookListener; interface IBookManager{ List<Book> getBookList(); void addBook(in Book book); void register(OnNewBookListener listener); void unregister(OnNewBookListener listener); }

创建完成后会在在gen下生成对应的IBookManager.java文件

创建IBookManager的实现类,并重写抽象方法

public class MyBinder extends IBookManager.Stub{/**     * 图书列表 线程安全     */    private CopyOnWriteArrayList<Book> bookList=new CopyOnWriteArrayList<Book>();    /**     * 观察者列表 对象不能跨进程传递 删除观察者需要用到此列表     */    private RemoteCallbackList<OnNewBookListener> listenerList=new RemoteCallbackList<OnNewBookListener>();        @Override        public List<Book> getBookList() throws RemoteException {            // TODO Auto-generated method stub            Log.i("TAG", "getBookList thread is "+Thread.currentThread().getName());            return bookList;        }        @Override        public void addBook(Book book) throws RemoteException {            // TODO Auto-generated method stub            bookList.add(book);        }        @Override        public void register(OnNewBookListener listener) throws RemoteException {            // TODO Auto-generated method stub            listenerList.register(listener);        }        @Override        public void unregister(OnNewBookListener listener)                throws RemoteException {            // TODO Auto-generated method stub            listenerList.unregister(listener);        }    }

这里是多个进程访问通一个数据,需要用到安全的CopyOnWriteArrayList来做线程同步,
接口集合不能用List,因为跨进程是不能传输对象的,对象跨进程传输的本质的序列化和反序列化,虽然在客户端在注册和注销上传递的是同一个对象,但是在远程service这边收到的是不同的对象,就会导致不能正常删除观察者,使用RemoteCallbackList可以解决这一问题。

创建远程service
在onbind中返回MyBinder的实例即可

@Override    public IBinder onBind(Intent intent) {        // TODO: Return the communication channel to the service.        return new MyBinder();    }

客户端代码
首先把服务器端的aidl文件放到自己项目中,注意包名一致
通过 bindService(intent, conn,BIND_AUTO_CREATE )既可以连接远程服务器
在连接成功后,会回调ServiceConnection实现类的 onServiceConnected方法 ,在使用IBookManager.Stub的asInterface方法把IBinder转换成对应的接口类型就可以正常使用了。

0 0