码迷,mamicode.com
首页 > 其他好文 > 详细

使用AIDL

时间:2016-06-03 19:20:59      阅读:220      评论:0      收藏:0      [点我收藏+]

标签:

转载请注明出处: 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.aidl
package com.blueberry.aidl;

//声明Book
parcelable Book ;

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

// IBookManager.aidl
package 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.aidl
package com.blueberry.aidl;

// Declare any non-default types here with import statements

import com.blueberry.aidl.Book;

interface OnBookArrivedListener {
  void  onBookArrived(in Book book) ;
}

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

// IBookManager.aidl
package 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.
所以这种方法可行。

使用AIDL

标签:

原文地址:http://blog.csdn.net/a992036795/article/details/51579711

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!