Android學(xué)習(xí)之介紹Binder的簡單使用
前言
最近因?yàn)楣卷?xiàng)目需求,需要遠(yuǎn)程調(diào)度啟動(dòng)客戶端輸入法輸入內(nèi)容。

這就是大致的需求流程,這篇首先講遠(yuǎn)程與服務(wù)控制端通訊。首先控制服務(wù)端定義好一個(gè)Service,且在ServiceManager注冊添加服務(wù)。
在這里我講解遠(yuǎn)程端與服務(wù)控制端通訊(主要通過C++往ServiceManager注冊服務(wù))。
首先我們得獲取到服務(wù)控制端注冊在ServiceManager的服務(wù)IBinder對象,通過Java反射機(jī)制獲得Ibinder接口對象。
public static IBinder getRemoteBinder(){
try {
Class<?> serviceManager = Class.forName("android.os.ServiceManager");
Method getService = serviceManager.getMethod("getService", String.class);
IBinder iBinder = (IBinder) getService.invoke(serviceManager.newInstance(), "InputService");
if(iBinder==null){
Log.e(PinyinIME.TAG,"getService InputService : is empty");
printServerList();//打印系統(tǒng)所提供的所有服務(wù)
}
return iBinder;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return null;
}
//具體源碼在android.os.ServiceManager
/**
* Returns a reference to a service with the given name.
*
* @param name the name of the service to get
* @return a reference to the service, or <code>null</code> if the service doesn't exist
*/
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
獲取到IBinder對象作用是跨進(jìn)程,舉個(gè)例子,輸入法程序是怎么和應(yīng)用編輯框通訊的呢?怎么通過什么控制輸入法彈起隱藏的呢。也是通過這個(gè)IBinder來通訊的,不信你翻翻源碼,這里不做詳細(xì)介紹。
而服務(wù)控制端則是由C++層注入服務(wù):
class IServiceManager : public IInterface
{
public:
DECLARE_META_INTERFACE(ServiceManager);
/**
* Retrieve an existing service, blocking for a few seconds
* if it doesn't yet exist.
*/
virtual sp<IBinder> getService( const String16& name) const = 0;
/**
* Retrieve an existing service, non-blocking.
*/
virtual sp<IBinder> checkService( const String16& name) const = 0;
/**
* Register a service.
*/
virtual status_t addService( const String16& name,
const sp<IBinder>& service,
bool allowIsolated = false) = 0;
/**
* Return list of all existing services.
*/
virtual Vector<String16> listServices() = 0;
enum {
GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION,
};
};
//上面C++層注冊服務(wù)提供一個(gè)IBinder接口子類,需要實(shí)現(xiàn)onTransact方法
virtual status_t onTransact(uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0)
{
LOGD("enter MyService onTransact and the code is %d", code);
switch (code)
{
case BINDER_HANDLE:
LOGD("MyService interface handle");
reply->writeCString("handle reply");
break;
case BINDER_SET_SCREEN:
LOGD("MyService interface set screen");
reply->writeCString("set screen reply");
break;
case BINDER_SET_CHAR:
{//call cb
LOGD("MyService interface set char before");
reply->writeCString("set char reply");
cb = data.readStrongBinder();
if (cb != NULL)
{
LOGD("MyService interface set char : %s", data.readCString());
Parcel in, out;
in.writeInterfaceToken(String16(BINDER_NAME));
in.writeInt32(n++);
in.writeString16(String16("This is a string."));
cb->transact(1, in, &out, 0);
show();
}
break;
}
default:
return BBinder::onTransact(code, data, reply, flags);
}
return 0;
}
這樣我們可以通過剛剛獲取到IBinder對象與之通訊了,這里我只講個(gè)例子:
當(dāng)遠(yuǎn)程端設(shè)備輸入法激活的時(shí)候,我將傳遞輸入法輸入類型和輸入法展示的多功能鍵傳遞給服務(wù)控制端。
//當(dāng)輸入法被激活的時(shí)候,會(huì)調(diào)用onStartInputView(EditorInfo,boolean)
Parcel data = Parcel.obtain();
data.writeInt(editorInfo.inputType);
data.writeInt(editorInfo.imeOptions);
Log.d(TAG, "isActives:" + isActives);
if (isActives) {
if (mController != null) {
mController.startInput(data, Parcel.obtain());
} else {
isNeedActives = true;
tmp = data;
mController = new Controller(remoteBinder,this);
}
} else {
isNeedActives = true;
tmp = data;
if (mController != null) {
mController.serviceConnection();
} else {
mController = new Controller(remoteBinder,this);
}
}
//這里我將兩個(gè)int參數(shù)寫入到Parce對象中開始進(jìn)行通訊
/**
* 開始輸入
*
* @param data
* 寫入輸入類型和多功能
* @param reply
*/
public void startInput(final Parcel data, final Parcel reply) {
Log.d(PinyinIME.TAG, getClass().getName() + ":\t startInput");
if (!PinyinIME.isActives) {
Log.d(PinyinIME.TAG, "not yet check success , start input failure");
dealHandler.sendEmptyMessage(Constant.HANDER_RELINK);
return;
}
new Thread(new Runnable() {
@Override
public void run() {
if (remoteBinder != null && remoteBinder.isBinderAlive()) {
try {
if (remoteBinder.transact(
Constant.INPUT_METHOD_ACTIVATION, data, reply,
IBinder.FLAG_ONEWAY)) {
PinyinIME.isNeedActives = false;
Log.d(PinyinIME.TAG,
"input method to activate, notify the success");
} else {
Log.d(PinyinIME.TAG,
"input method to activate, notify the failure");
}
} catch (RemoteException e) {
e.printStackTrace();
} finally {
data.recycle();
reply.recycle();
}
}else{
dealHandler.sendEmptyMessage(Constant.HANDER_RELINK);
}
}
}).start();
}
這樣我們就可以通過獲取到的Ibinder對象的transact方法進(jìn)行通訊。
//code必須雙方定義好,否則接收數(shù)據(jù)無法正常, //第一個(gè)是我們裝載的序列化數(shù)據(jù), //第二我們可以直接傳個(gè)對象,最好一個(gè)是需要返回結(jié)果的標(biāo)識(shí), //0代表需要返回內(nèi)容,FLAG_ONEWAY單方面無需返回結(jié)果的標(biāo)識(shí) public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException;
當(dāng)我們調(diào)用了ibinder.transact(int,parce,parce,int)方法,這是注冊的服務(wù)中的IBinder對象的onTransact(int,parce,parce,int)方法就會(huì)被響應(yīng),這樣我們就實(shí)現(xiàn)了遠(yuǎn)程端跟服務(wù)控制端通訊了。
到了這里,有個(gè)問題,服務(wù)控制端接收到客戶端輸入的內(nèi)容咋辦,怎通知遠(yuǎn)程端輸入法輸入內(nèi)容到編輯框中呢。
其實(shí)也很簡單,我們只需要在遠(yuǎn)程端輸入法程序?qū)崿F(xiàn)一個(gè)Ibinder對象,傳遞給服務(wù)控制端,這樣就可以實(shí)現(xiàn),具體怎么傳遞了?
//首先我們得讓遠(yuǎn)程輸入法程序擁有屬于自己的ibinder類。
package com.redfinger.inputmethod.server;
import com.android.inputmethod.pinyin.PinyinIME;
import android.annotation.SuppressLint;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
import android.view.KeyEvent;
public interface InputBinder extends IInterface{
public static class Stub extends Binder implements InputBinder{
private static final java.lang.String DESCRIPTOR = "com.redfinger.inputmethod.service.InputBinder";
public PinyinIME pinyinIME;
public Stub(PinyinIME pinyinIME) {
this.pinyinIME = pinyinIME;
this.attachInterface(this, DESCRIPTOR);
}
public InputBinder asInterface(IBinder obj){
if(obj == null){
return null;
}
IInterface iInterface = obj.queryLocalInterface(DESCRIPTOR);
if(iInterface!=null&&iInterface instanceof InputBinder){
return (InputBinder)iInterface;
}
return new Stub.Proxy(obj);
}
@Override
public IBinder asBinder() {
return this;
}
@SuppressLint({ "NewApi", "Recycle" })
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
switch (code) {
case Constant.CONNECTION_HANDSHAKE2:
String dataString = data.readString();
Log.d(PinyinIME.TAG, "The second handshake start [data = "+dataString +"]");
if("CONNECTION_RESPONED".equals(dataString)){
Parcel parcel = Parcel.obtain();
parcel.writeString("CONNECTION_FINISH");
pinyinIME.getRemoteBinder().transact(Constant.CONNECTION_HANDSHAKE3, parcel, Parcel.obtain(), IBinder.FLAG_ONEWAY);
PinyinIME.isActives = true;
Log.d(PinyinIME.TAG, "The third handshake success");
if (PinyinIME.isNeedActives) {
PinyinIME.mController.startInput(pinyinIME.getTmp(), Parcel.obtain());
}
if (PinyinIME.isNeedCloseInputMethod) {
PinyinIME.mController.finishInput();
}
}else{
Log.d(PinyinIME.TAG, "The third handshake failure , agent connect ! ");
PinyinIME.mController.serviceConnection();
}
break;
case Constant.FUNCTION_INPUT:
....
switch (keyCode) {
case 14:
pinyinIME.simulateKeyEventDownUp(KeyEvent.KEYCODE_DEL);
return true;
case 28:
pinyinIME.simulateKeyEventDownUp(KeyEvent.KEYCODE_ENTER);
return true;
case 65:
pinyinIME.requestHideSelfFromClient = true;
pinyinIME.requestHideSelf(0);
break;
}
break;
case Constant.CHARACTER_INPUT:
....
return true;
case Constant.DISCONNECTION:
....
break;
case Constant.INPUT_METHOD_PLATFORM:
....
break;
}
return super.onTransact(code, data, reply, flags);
}
public static class Proxy implements InputBinder{
private android.os.IBinder mRemote;
public Proxy(android.os.IBinder mRemote) {
this.mRemote = mRemote;
}
@Override
public IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
}
static final int receiveChar = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
}
是不是特變像AIDL文件的內(nèi)容一樣,aidl其實(shí)就是Android自己給我寫好的ibinder代碼一樣。
這樣我們就可以在獲取到服務(wù)控制端ibinder對象中寫入我們自己ibinder對象,傳遞過去讓他通過transact方法來與輸入法程序ibinder對象通訊了。
//Parce類中提供了這樣的一個(gè)方法,就是用于寫入ibinder對象的。
public final void writeStrongBinder(IBinder val) {
nativeWriteStrongBinder(mNativePtr, val);
}
這樣我們就可以在InputBinder類中來處理返回的數(shù)據(jù)了。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。
相關(guān)文章
詳解Android studio 3+版本apk安裝失敗問題
這篇文章主要介紹了詳解Android studio 3+版本apk安裝失敗問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
Android編程之SurfaceView學(xué)習(xí)示例詳解
這篇文章主要介紹了Android編程之SurfaceView學(xué)習(xí)示例,結(jié)合實(shí)例分析了SurfaceView的功能、使用方法與注意事項(xiàng),具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10
Android自定義ViewGroup實(shí)現(xiàn)標(biāo)簽流效果
這篇文章主要為大家詳細(xì)介紹了Android自定義ViewGroup實(shí)現(xiàn)標(biāo)簽流效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06

