2.3 IPC基礎(chǔ)概念介紹(三)

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性質(zhì)的接口,只需要繼承IInterface接口(接口繼承接口)。定義兩個業(yè)務(wù)方法和對應(yīng)的ID,以及binder特有的唯一標(biāo)識符DESCRIPTOR,一般為完整類名。

2. 實現(xiàn)Stub類

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

    @Override
    public List<Book> getBookList() throws RemoteException {
        // 待實現(xiàn)
        return null;
    }

    @Override
    public void addBook(Book book) throws RemoteException {
        // 待實現(xiàn)
    }

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

3. 添加Stub的子類Proxy

/**
 * Cast an IBinder object into an IBookManager interface,
 * generating a proxy if needed.
 * <p/>
 * 客戶端連接服務(wù)端會通過該方法獲得Binder,根據(jù)是否跨應(yīng)用會返回IBookManager或者代理Proxy.
 * 跨應(yīng)用時返回代理,客戶端拿到代理,調(diào)用方法時,實際是transact方法去調(diào)用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 {}

如果要調(diào)用binder中的onTransact方法,調(diào)用transact即可。transact是IBinder中定義的方法,Binder實現(xiàn)了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;
}

可見其中調(diào)用了onTransact方法,在方法之前和之后做了處理。之前把輸入型對象data的dataPosition設(shè)為0;之后把輸出型對象reply的dataPosition設(shè)為0.
transact翻譯為辦理,binder在里面處理業(yè)務(wù)。根據(jù)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);
}

開發(fā)中我們可以使用aidl,aidl的意義在于為我們提供了一種快速實現(xiàn)Binder的工具。它不是實現(xiàn)Binder的必須品,我們可以手寫B(tài)inder。

5. 本應(yīng)用使用自定義的Binder

public class ManualService extends Service {
    // 服務(wù)中的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-調(diào)用getBookList方法
    bookManager.getBookList();
    // onDestroy
}

6. 跨應(yīng)用調(diào)用服務(wù)

和aidl一樣,首先創(chuàng)建包名類名一樣的幾個文件

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

客戶端調(diào)用

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點擊事件調(diào)用服務(wù)端方法
iBookManager.getBookList();

7. likeToDeath和unlikeToDeath

Binder運(yùn)行在服務(wù)端,如果服務(wù)端進(jìn)程由于某種原因異常終止,這個時候我們連接服務(wù)端的Binder連接斷裂(稱之為Binder死亡),會導(dǎo)致我們的遠(yuǎn)程調(diào)用失敗。
如果我們不知道Binder連接已經(jīng)斷裂,那么客戶端的功能就會受影響。解決方法是給Binder設(shè)置死亡代理,當(dāng)Binder死亡時,我們就會收到通知,這個時候我們就可以重新發(fā)起連接請求從而恢復(fù)連接。

// 定義死亡代理 recipient翻譯為收件人
 final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
    @Override
    public void binderDied() {
        // binder死亡時,會回調(diào)這個方法
        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);
        // 設(shè)置死亡代理
        service.linkToDeath(mDeathRecipient,0);
    }

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

8. isBinderAlive

該方法用于判斷Binder的狀態(tài)

bookManager.asBinder().isBinderAlive();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容