使用AIDL

来源:互联网 发布:封窗户 知乎 编辑:程序博客网 时间:2024/06/04 18:59

转载请注明出处: http://blog.csdn.net/a992036795/article/details/51579711

一、什么是aidl?
AIDL是android内部一种进程通信接口的描述语言。

二、使用aidl
aidl支持的数据类型:

  • 基本数据类型 (int 、long、char 、boolean、double 等)
  • String 和CharSequence
  • List:只支持ArrayList,里面每个元素都必须能够被AIDL支持。
  • Map:只支持HashMap,里面的每个元素都必须被AIDL支持,包括key和value.
  • Pracelable,所有实现Pracelable接口的对象。
  • AIDL:所有的AIDL接口本身也可以在aidl文件中使用。

    我们来写一个例子:假设服务端是一个图书馆,用来管理图书。而客户端用来添加书籍,和获得所有图书信息。
    那么首先我们需要一个类来用来描述图书信息,其次我们的这个类必须实现Parcelable接口,因为要夸进程传输。
    所以就有Book.java定义如下:

package com.blueberry.aidl;import android.os.Parcel;import android.os.Parcelable;/** * Created by blueberry on 2016/6/3. */public class Book implements Parcelable{    public int bookId ;    public String bookName ;    protected Book(Parcel in) {        bookId = in.readInt();        bookName = in.readString();    }    public Book() {    }    public Book(String bookName, int bookId) {        this.bookName = bookName;        this.bookId = bookId;    }    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeInt(bookId);        dest.writeString(bookName);    }    @Override    public String toString() {        return "Book{" +                "bookId=" + bookId +                ", bookName='" + bookName + '\'' +                '}';    }    public static final Creator<Book> CREATOR = new Creator<Book>() {        @Override        public Book createFromParcel(Parcel in) {            return new Book(in);        }        @Override        public Book[] newArray(int size) {            return new Book[size];        }    };}

注意其中必须重写writeToParcel()方法,以及必须要有一个内部类CREATOR用来反序列化。
下面我们创建Book对应的aidl文件,来声明Book类。
Book.aidl文件:

// Book.aidlpackage com.blueberry.aidl;//声明Bookparcelable Book ;

接着我们需要一个BookManager接口来实现客户端对服务端的调用
IBookManager.aidl:

// IBookManager.aidlpackage com.blueberry.aidl;//即使在同一个包下也要声明import com.blueberry.aidl.Book;import com.blueberry.aidl.OnBookArrivedListener;interface IBookManager {    /**    * 获得Books,实际传递的是ArrayList    */    List<Book> getBookList();    /**    * 添加Book    */    void addBook(in Book book);}

注意 addBook()方法 java中接口的参数声明多一个描述符,in,来描述参数传递的方向,可以为in ,out或者 inout。in表示输入型参数,out表示输出型参数,inout表示输入输出参数。另外aidl接口描述中,不支持声明静态常量,这一点区别于传统的接口。

那么aidl文件写完了,我们编译一下看看,对应的文件夹下生成的java,文件
我这里先全部贴出:

/* * This file is auto-generated.  DO NOT MODIFY. * Original file: E:\\AsWorkSpace\\test\\test04\\app\\src\\main\\aidl\\com\\blueberry\\aidl\\IBookManager.aidl */package com.blueberry.aidl;public interface IBookManager extends android.os.IInterface {    /**     * Local-side IPC implementation stub class.     */    public static abstract class Stub extends android.os.Binder implements com.blueberry.aidl.IBookManager {        private static final java.lang.String DESCRIPTOR = "com.blueberry.aidl.IBookManager";        /**         * Construct the stub at attach it to the interface.         */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an com.blueberry.aidl.IBookManager interface,         * generating a proxy if needed.         */        public static com.blueberry.aidl.IBookManager asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.blueberry.aidl.IBookManager))) {                return ((com.blueberry.aidl.IBookManager) iin);            }            return new com.blueberry.aidl.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.blueberry.aidl.Book> _result = this.getBookList();                    reply.writeNoException();                    reply.writeTypedList(_result);                    return true;                }                case TRANSACTION_addBook: {                    data.enforceInterface(DESCRIPTOR);                    com.blueberry.aidl.Book _arg0;                    if ((0 != data.readInt())) {                        _arg0 = com.blueberry.aidl.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.blueberry.aidl.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;            }            /**             * 获得Books,实际传递的是ArrayList             */            @Override            public java.util.List<com.blueberry.aidl.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.blueberry.aidl.Book> _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);                    _reply.readException();                    _result = _reply.createTypedArrayList(com.blueberry.aidl.Book.CREATOR);                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }            /**             * 添加Book             */            @Override            public void addBook(com.blueberry.aidl.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);    }    /**     * 获得Books,实际传递的是ArrayList     */    public java.util.List<com.blueberry.aidl.Book> getBookList() throws android.os.RemoteException;    /**     * 添加Book     */    public void addBook(com.blueberry.aidl.Book book) throws android.os.RemoteException;}

可以看到这个文件主要有一个接口(IBookManager)和2个实现类(Stub、Proxy)。
我们可以看到 IBookManager实际就是我们在aidl文件中定义的那个接口,只是它继承了一个IInterface接口。看看IInterface接口的描述:

/** * Base class for Binder interfaces.  When defining a new interface, * you must derive it from IInterface. */public interface IInterface{    /**     * Retrieve the Binder object associated with this interface.     * You must use this instead of a plain cast, so that proxy objects     * can return the correct result.     */    public IBinder asBinder();}

可以看到使用binder通信,每个接口都必须继承自这个接口 。
我们现在来看Stub类的定义:

public static abstract class Stub extends android.os.Binder implements com.blueberry.aidl.IBookManager {        private static final java.lang.String DESCRIPTOR = "com.blueberry.aidl.IBookManager";        /**         * Construct the stub at attach it to the interface.         */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an com.blueberry.aidl.IBookManager interface,         * generating a proxy if needed.         */        public static com.blueberry.aidl.IBookManager asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.blueberry.aidl.IBookManager))) {                return ((com.blueberry.aidl.IBookManager) iin);            }            return new com.blueberry.aidl.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.blueberry.aidl.Book> _result = this.getBookList();                    reply.writeNoException();                    reply.writeTypedList(_result);                    return true;                }                case TRANSACTION_addBook: {                    data.enforceInterface(DESCRIPTOR);                    com.blueberry.aidl.Book _arg0;                    if ((0 != data.readInt())) {                        _arg0 = com.blueberry.aidl.Book.CREATOR.createFromParcel(data);                    } else {                        _arg0 = null;                    }                    this.addBook(_arg0);                    reply.writeNoException();                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }    } static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);        static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

可以看到它继承自Binder,并实现了IBookManager的asBinder()方法,但并没有实现IBookManager的addBook()和getBookList()方法,这些犯法最终留给他的子类去是实现。
首先,看他的的构造方法:

   private static final java.lang.String DESCRIPTOR = "com.blueberry.aidl.IBookManager"; public Stub() {            this.attachInterface(this, DESCRIPTOR);        }

它将调用父类binder的 attachInterface方法,将自身,以及他的描述符传递类进去。我们可以看看这个方法的定义:

 /**     * Convenience method for associating a specific interface with the Binder.     * After calling, queryLocalInterface() will be implemented for you     * to return the given owner IInterface when the corresponding     * descriptor is requested.     */    public void attachInterface(IInterface owner, String descriptor) {        mOwner = owner;        mDescriptor = descriptor;    }

这里的大致意思是:调用这个方法之后,我们到时可以使用queryLocalnterface()这个方法传入描述符DESTRIPTOR来找到这个binder.

所以紧接着就有这个方法:

 /**         * Cast an IBinder object into an com.blueberry.aidl.IBookManager interface,         * generating a proxy if needed.         */        public static com.blueberry.aidl.IBookManager asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.blueberry.aidl.IBookManager))) {                return ((com.blueberry.aidl.IBookManager) iin);            }            return new com.blueberry.aidl.IBookManager.Stub.Proxy(obj);        }

这里调用queryLocalInterface()来查询本地是否有这个binder.如果有的话,就将本地的这个binder返回,否则的话将使用 这个binder对象构造出一个代理类Proxy返回。

这里就说明了如果本地有这个binder,就使用本地的这个binder。否则这个binder就是远程的,那我就将这个binder作为参数构造出一个代理类Proxy来使用。

那我们就先放下onTransact()方法,来看Proxy类。实际上onTransact()方法实在夸进程调时才会调用,而且实在服务端被调用。

我们先看Proxy类:

  private static class Proxy implements com.blueberry.aidl.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;            }            /**             * 获得Books,实际传递的是ArrayList             */            @Override            public java.util.List<com.blueberry.aidl.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.blueberry.aidl.Book> _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);                    _reply.readException();                    _result = _reply.createTypedArrayList(com.blueberry.aidl.Book.CREATOR);                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }            /**             * 添加Book             */            @Override            public void addBook(com.blueberry.aidl.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();                }            }        }

这个很明显是一个代理模式,在构造方法将被代理的类传递进来,然后真正是在执行这个类的方法,实际就是执行mRemote的方法。

 private android.os.IBinder mRemote;            Proxy(android.os.IBinder remote) {                mRemote = remote;            }

我们接着来看他的 getBookList()方法和addBook()方法

  /**             * 获得Books,实际传递的是ArrayList             */            @Override            public java.util.List<com.blueberry.aidl.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.blueberry.aidl.Book> _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);                    _reply.readException();                    _result = _reply.createTypedArrayList(com.blueberry.aidl.Book.CREATOR);                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }            /**             * 添加Book             */            @Override            public void addBook(com.blueberry.aidl.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();                }            }

我们可以看到,他使用Parcel创建 出输入参数,以及返回参数最后是调用了被代理类即 mRemote的 transact方法。因为这个mRemote是远程服务端传递过来的。
所以这个方法的调用执行将发生在服务端。
我们来看一下这个方法子在Binder中的定义:

  /**     * Default implementation rewinds the parcels and calls onTransact.  On     * the remote side, transact calls into the binder to do the IPC.     */    public final boolean transact(int code, Parcel data, Parcel reply,            int flags) throws RemoteException {        if (false) Log.v("Binder", "Transact: " + code + " to " + this);        if (data != null) {            data.setDataPosition(0);        }        boolean r = onTransact(code, data, reply, flags);        if (reply != null) {            reply.setDataPosition(0);        }        return r;    }

我们可以看到最后执行了 它的onTransact()方法。
那么,现在我们就明白了。因为服务端和客户端有着同样的aidl文件,这个远程对象实际是 服务端那边声明的Stub类,它将执行的是Stub类中onTransact()方法
那么我们就来看,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_getBookList: {                    data.enforceInterface(DESCRIPTOR);                    java.util.List<com.blueberry.aidl.Book> _result = this.getBookList();                    reply.writeNoException();                    reply.writeTypedList(_result);                    return true;                }                case TRANSACTION_addBook: {                    data.enforceInterface(DESCRIPTOR);                    com.blueberry.aidl.Book _arg0;                    if ((0 != data.readInt())) {                        _arg0 = com.blueberry.aidl.Book.CREATOR.createFromParcel(data);                    } else {                        _arg0 = null;                    }                    this.addBook(_arg0);                    reply.writeNoException();                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }

可以看到,他最终调用了服务端Stub的 addBook()方法以及getBookList()方法。
这2个方法最后发生在服务端。
这样就完成了一次原生调用。

三、接着我贴一下服务端Service的实现,以及客户端的调用。

public class SimpleService extends Service {    private static final String TAG = "SimpleService";    private CopyOnWriteArrayList<Book> books = new CopyOnWriteArrayList<>();    @Nullable    @Override    public IBinder onBind(Intent intent) {        return new IBookManager.Stub(){            @Override            public List<Book> getBookList() throws RemoteException {                Log.i(TAG, "getBookList: books: " +books);                Log.i(TAG, "current Thread :" +Thread.currentThread());                return books;            }            @Override            public void addBook(Book book) throws RemoteException {                Log.i(TAG, "addBook: book: "+book);                Log.i(TAG, "current Thread :"+Thread.currentThread());                books.add(book);            }        };    }}
public class MainActivity extends AppCompatActivity {    private static final String TAG = "MainActivity";    private Button btnAdd,btnGet;    private TextView tvLog;    private int count;    private IBookManager mBookManager;    private ServiceConnection conn = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            mBookManager = IBookManager.Stub.asInterface(service) ;            Log.i(TAG, "onServiceConnected: ");        }        @Override        public void onServiceDisconnected(ComponentName name) {            Log.i(TAG, "onServiceDisconnected: ");        }    } ;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Intent intent = new Intent(this,SimpleService.class);        bindService(intent,conn, Context.BIND_AUTO_CREATE);        initView();    }    private void initView() {        btnAdd = (Button) findViewById(R.id.btn_add);        btnGet = (Button) findViewById(R.id.btn_get);        tvLog = (TextView) findViewById(R.id.tv_log);        btnAdd.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Book book = new Book(count,"book#"+count);                count++;                try {                    mBookManager.addBook(book);                } catch (RemoteException e) {                    e.printStackTrace();                }                Log.i(TAG, "add book :"+book);                Log.i(TAG, "current thread: "+Thread.currentThread());            }        });        btnGet.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                try {                    List<Book> books = mBookManager.getBookList();                    Log.i(TAG, "books :"+books);                    Log.i(TAG, "current thread: "+Thread.currentThread());                    tvLog.setText("");                    for(Book book:books){                        tvLog.append(book.toString());                        tvLog.append("\n");                    }                } catch (RemoteException e) {                    e.printStackTrace();                }            }        });    }}

四、可以为binder设置死亡代理,这样在binder销毁之后我们就可以接受到消息。

private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {        @Override        public void binderDied() {            Log.i(TAG, "binderDied: ");        }    } ;    private ServiceConnection conn = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            mBookManager = IBookManager.Stub.asInterface(service) ;            try {                /*设置死亡代理*/                service.linkToDeath(mDeathRecipient ,0 );            } catch (RemoteException e) {                e.printStackTrace();            }            Log.i(TAG, "onServiceConnected: ");        }        @Override        public void onServiceDisconnected(ComponentName name) {            Log.i(TAG, "onServiceDisconnected: ");        }    } ;

五、最后在扩展一个
假如我们不想每次都使用getBookList来获取图书列表,我们希望客户端可以在服务端设置一个监听器。使得客户端可以接受服务端的消息回调。

那么我们就需要定义一个接口来定义回调方法,因为是夸进程所以我们需要使用aidl文件来定义。

// OnBookArrivedListener.aidlpackage com.blueberry.aidl;// Declare any non-default types here with import statementsimport com.blueberry.aidl.Book;interface OnBookArrivedListener {  void  onBookArrived(in Book book) ;}

还需要在IBookManager.aidl添加2个方法用来 注册观察着,和移除观察者。

// IBookManager.aidlpackage com.blueberry.aidl;//即使在同一个包下也要声明import com.blueberry.aidl.Book;import com.blueberry.aidl.OnBookArrivedListener;interface IBookManager {    /**    * 获得Books,实际传递的是ArrayList    */    List<Book> getBookList();    /**    * 添加Book    */    void addBook(in Book book);    /**    * 添加监听器    */    void registerListener(in OnBookArrivedListener listener) ;    /**    * 移除监听器    */    void remoteListener(in OnBookArrivedListener listener);}

同样我们需要在服务端 用一个容器来存储这些观察者。

package com.blueberry.test04;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteCallbackList;import android.os.RemoteException;import android.util.Log;import com.blueberry.aidl.Book;import com.blueberry.aidl.IBookManager;import com.blueberry.aidl.OnBookArrivedListener;import java.util.List;import java.util.concurrent.CopyOnWriteArrayList;public class SimpleService extends Service {    private static final String TAG = "SimpleService";    /*最终会将CopyOnWriteArrayList转化为ArrayList进行夸进程传输*/    private CopyOnWriteArrayList<Book> books = new CopyOnWriteArrayList<>() ;    /**     * RemoteCallbackList     */    private RemoteCallbackList<OnBookArrivedListener> listeners = new RemoteCallbackList<>() ;    private IBookManager.Stub stub =new IBookManager.Stub(){        @Override        public List<Book> getBookList() throws RemoteException {            Log.i(TAG, "current thread: "+Thread.currentThread());            Log.i(TAG, "getBookList: Books.class: "+books.getClass());            return books;        }        @Override        public void addBook(Book book) throws RemoteException {            Log.i(TAG, "current thread: "+Thread.currentThread());            Log.i(TAG, "addBook: book: "+book);            books.add(book) ;         int N =  listeners.beginBroadcast();            for (int i = 0; i < N; i++) {                OnBookArrivedListener broadcastItem = listeners.getBroadcastItem(i);                if(broadcastItem!=null){                    try {                        broadcastItem.onBookArrived(book);                    }catch (RemoteException e){                        e.printStackTrace();                    }                }            }            listeners.finishBroadcast();        }        @Override        public void registerListener(OnBookArrivedListener listener) throws RemoteException {           listeners.register(listener) ;        }        @Override        public void remoteListener(OnBookArrivedListener listener) throws RemoteException {           listeners.unregister(listener);            Log.i(TAG, "remoteListener: ok.");        }    };    public SimpleService() {    }    private int count = 0;    @Override    public IBinder onBind(Intent intent) {        new Thread(){            @Override            public void run() {               while (true){                   try {                       Thread.sleep(2000);                   } catch (InterruptedException e) {                       e.printStackTrace();                   }                   Book book = new Book("book#"+count,count);                   count++ ;                   try {                       stub.addBook(book);                   } catch (RemoteException e) {                       e.printStackTrace();                   }               }            }        }.start();        return stub ;    }    @Override    public void onDestroy() {        super.onDestroy();        Log.i(TAG, "onDestroy: ");    }}

注意我并没有使用CopyOnWriteArrayList来存储观察着们,原因是:
如果使用这种集合,我们在取消注册观察者即调用remoteListener(OnBookArrivedListener listener)将会无作用,会因为这个参数中传递过来的对象,在跨进程时将会被序列化,以及反序列化。将导致和服务端的不是同一个对象,所以不会移除的这个监听器。

所以我们选择使用RemoteCallbackList 来存储。RemoteCallbakList使用一个ArrayMap< IBinder, Callback> 来存数这些监听着们。
我们来看一下它的register方法 和remove方法

   */    public boolean register(E callback, Object cookie) {        synchronized (mCallbacks) {            if (mKilled) {                return false;            }            IBinder binder = callback.asBinder();            try {                Callback cb = new Callback(callback, cookie);                binder.linkToDeath(cb, 0);                mCallbacks.put(binder, cb);                return true;            } catch (RemoteException e) {                return false;            }        }    }
  public boolean unregister(E callback) {        synchronized (mCallbacks) {            Callback cb = mCallbacks.remove(callback.asBinder());            if (cb != null) {                cb.mCallback.asBinder().unlinkToDeath(cb, 0);                return true;            }            return false;        }    }

可以看到它调用监听器的 asBinder()方法作为键来存储对象,
我们上文分析过Stub、和Proxy类,知道Stub返回的 this, Proxy返回的是mRemote。 而如果是夸进程时,这个mRemote正时服务端Stub返回的this.
所以这种方法可行。

0 0
原创粉丝点击