2.3 IPC基础概念介绍(三)

2016-06-16  本文已影响100人  武安长空

1. 定义IBookManager接口

public interface IBookManager extends IInterface {
    static final java.lang.String DESCRIPTOR = "qingfengmy.developmentofart._2activity.Manual.IBookManager";

    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<qingfengmy.developmentofart._2activity.aidl.Book> getBookList() throws android.os.RemoteException;

    public void addBook(qingfengmy.developmentofart._2activity.aidl.Book book) throws android.os.RemoteException;
}

声明一个aidl性质的接口,只需要继承IInterface接口(接口继承接口)。定义两个业务方法和对应的ID,以及binder特有的唯一标识符DESCRIPTOR,一般为完整类名。

2. 实现Stub类

public class BookManagerImpl extends Binder implements IBookManager {
    /**
     * Construct the stub at attach it to the interface.
     * 构建连接到接口的stub
     */
    public BookManagerImpl() {
        this.attachInterface(this, DESCRIPTOR);
    }

    @Override
    public List<Book> getBookList() throws RemoteException {
        // 待实现
        return null;
    }

    @Override
    public void addBook(Book book) throws RemoteException {
        // 待实现
    }

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

3. 添加Stub的子类Proxy

/**
 * Cast an IBinder object into an IBookManager interface,
 * generating a proxy if needed.
 * <p/>
 * 客户端连接服务端会通过该方法获得Binder,根据是否跨应用会返回IBookManager或者代理Proxy.
 * 跨应用时返回代理,客户端拿到代理,调用方法时,实际是transact方法去调用onTransact的。
 */
public static IBookManager asInterface(IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof IBookManager))) {
        return ((IBookManager) iin);
    }
    return new BookManagerImpl.Proxy(obj);
}

private static class Proxy implements IBookManager {
    private IBinder mRemote;

    Proxy(IBinder remote) {
        mRemote = remote;
    }

    @Override
    public android.os.IBinder asBinder() {
        return mRemote;
    }

    public java.lang.String getInterfaceDescriptor() {
        return DESCRIPTOR;
    }

    @Override
    public java.util.List<Book> getBookList() throws RemoteException {
        Parcel _data = Parcel.obtain();
        Parcel _reply = Parcel.obtain();
        List<Book> _result;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            mRemote.transact(TRANSACTION_getBookList, _data, _reply, 0);
            _reply.readException();
            _result = _reply.createTypedArrayList(Book.CREATOR);
        } finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    }

    @Override
    public void addBook(Book book) throws RemoteException {
        Parcel _data = Parcel.obtain();
        Parcel _reply = Parcel.obtain();
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            if ((book != null)) {
                _data.writeInt(1);
                book.writeToParcel(_data, 0);
            } else {
                _data.writeInt(0);
            }
            mRemote.transact(TRANSACTION_addBook, _data, _reply, 0);
            _reply.readException();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
    }
}

4. onTransact方法

Binder中的方法定义

/**
 * Default implementation is a stub that returns false.  You will want
 * to override this to do the appropriate unmarshalling of transactions.
 *
 * <p>If you want to call this, call transact().
 */
protected boolean onTransact(int code, Parcel data, Parcel reply,
        int flags) throws RemoteException {}

如果要调用binder中的onTransact方法,调用transact即可。transact是IBinder中定义的方法,Binder实现了IBinder,所以也有transact方法。如下

/**
 * 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方法,在方法之前和之后做了处理。之前把输入型对象data的dataPosition设为0;之后把输出型对象reply的dataPosition设为0.
transact翻译为办理,binder在里面处理业务。根据code判断是哪个方法,data是输入型,reply是输出型。

@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
    switch (code) {
        case INTERFACE_TRANSACTION: {
            reply.writeString(DESCRIPTOR);
            return true;
        }
        case TRANSACTION_getBookList: {
            data.enforceInterface(DESCRIPTOR);
            List<Book> _result = this.getBookList();
            reply.writeNoException();
            reply.writeTypedList(_result);
            return true;
        }
        case TRANSACTION_addBook: {
            data.enforceInterface(DESCRIPTOR);
            Book _arg0;
            if ((0 != data.readInt())) {
                _arg0 = Book.CREATOR.createFromParcel(data);
            } else {
                _arg0 = null;
            }
            this.addBook(_arg0);
            reply.writeNoException();
            return true;
        }
    }
    return super.onTransact(code, data, reply, flags);
}

开发中我们可以使用aidl,aidl的意义在于为我们提供了一种快速实现Binder的工具。它不是实现Binder的必须品,我们可以手写Binder。

5. 本应用使用自定义的Binder

public class ManualService extends Service {
    // 服务中的binder是private
    private BookManagerImpl bookManager;

    public ManualService() {
        bookManager = new BookManagerImpl();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return bookManager;
    }

}
public class ManualActivity extends AppCompatActivity {

    ServiceConnection serviceConnection;
    // 接口是暴露出来的
    IBookManager bookManager;
    Intent intent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_manual);

        serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                bookManager = BookManagerImpl.asInterface(service);
                Log.e("aaa","-----onServiceConnected-----");
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        };

        intent = new Intent(this, ManualService.class);
        bindService(intent, serviceConnection, BIND_AUTO_CREATE);

    }
    
    // click-调用getBookList方法
    bookManager.getBookList();
    // onDestroy
}

6. 跨应用调用服务

和aidl一样,首先创建包名类名一样的几个文件

qingfengmy.developmentofart._2activity.aidl.Book
qingfengmy.developmentofart._2activity.Manual.BookManagerImpl
qingfengmy.developmentofart._2activity.Manual.IBookManager

客户端调用

IBookManager iBookManager;
ServiceConnection serviceConnection;
Intent intent;

intent = new Intent();
intent.setAction("qingfengmy.developmentofart.ManualService");
intent.setPackage("qingfengmy.developmentofart");
serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        if (service != null) {
            iBookManager = BookManagerImpl.asInterface(service);
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};
bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE);

// click点击事件调用服务端方法
iBookManager.getBookList();

7. likeToDeath和unlikeToDeath

Binder运行在服务端,如果服务端进程由于某种原因异常终止,这个时候我们连接服务端的Binder连接断裂(称之为Binder死亡),会导致我们的远程调用失败。
如果我们不知道Binder连接已经断裂,那么客户端的功能就会受影响。解决方法是给Binder设置死亡代理,当Binder死亡时,我们就会收到通知,这个时候我们就可以重新发起连接请求从而恢复连接。

// 定义死亡代理 recipient翻译为收件人
 final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
    @Override
    public void binderDied() {
        // binder死亡时,会回调这个方法
        if (bookManager == null){
            return;
        }
        bookManager.asBinder().unlinkToDeath(this,0);
        bookManager = null;
        // 重连
        bindService(intent,serviceConnection,BIND_AUTO_CREATE);
    }
};
serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        bookManager = BookManagerImpl.asInterface(service);
        // 设置死亡代理
        service.linkToDeath(mDeathRecipient,0);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {}
};

8. isBinderAlive

该方法用于判断Binder的状态

bookManager.asBinder().isBinderAlive();
上一篇 下一篇

猜你喜欢

热点阅读