欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android學(xué)習(xí)之介紹Binder的簡單使用

 更新時(shí)間:2016年12月31日 14:56:06   作者:學(xué)海擺渡人  
BInder方面的資料雖然感覺看的比較多,但是真正用的時(shí)候才發(fā)現(xiàn)有很多地方模棱兩棵的,所以,打算用一個(gè)實(shí)例再來鞏固一下binder的使用方法。這篇文章主要介紹了Android中Binder的簡單使用,文中給出詳細(xì)的示例代碼,需要的朋友可以參考下

前言

最近因?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í)候,會調(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)識,
//0代表需要返回內(nèi)容,FLAG_ONEWAY單方面無需返回結(jié)果的標(biāo)識

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)方法就會被響應(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彈出窗口實(shí)現(xiàn)方法

    Android彈出窗口實(shí)現(xiàn)方法

    這篇文章主要介紹了Android彈出窗口實(shí)現(xiàn)方法,涉及Android TextView及鼠標(biāo)事件的響應(yīng)相關(guān)技巧,需要的朋友可以參考下
    2016-01-01
  • 詳解Android studio 3+版本apk安裝失敗問題

    詳解Android studio 3+版本apk安裝失敗問題

    這篇文章主要介紹了詳解Android studio 3+版本apk安裝失敗問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • 很實(shí)用的Android日期計(jì)算類

    很實(shí)用的Android日期計(jì)算類

    這篇文章主要為大家詳細(xì)介紹了很實(shí)用的Android日期計(jì)算類,一個(gè)是獲取與今天時(shí)間差,另一個(gè)是日期格式化工具類,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • 使用CursorLoader異步加載數(shù)據(jù)

    使用CursorLoader異步加載數(shù)據(jù)

    這篇文章主要為大家詳細(xì)介紹了使用CursorLoader異步加載數(shù)據(jù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • Android編程之SurfaceView學(xué)習(xí)示例詳解

    Android編程之SurfaceView學(xué)習(xí)示例詳解

    這篇文章主要介紹了Android編程之SurfaceView學(xué)習(xí)示例,結(jié)合實(shí)例分析了SurfaceView的功能、使用方法與注意事項(xiàng),具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • Android 錄制音視頻的完整代碼

    Android 錄制音視頻的完整代碼

    Android中,如果要錄制音頻的話有兩個(gè)選擇,一個(gè)是MediaRecorder,另一個(gè)就是AudioRecord,前者使用簡單,后者就相對復(fù)雜點(diǎn),本文通過代碼給大家介紹Android 錄制音視頻的相關(guān)知識,一起看看吧
    2021-06-06
  • Android中的Intent對象完全解析

    Android中的Intent對象完全解析

    這篇文章主要介紹了Android中的Intent對象,深入講解了intent對象傳遞消息的各種用法,需要的朋友可以參考下
    2016-04-04
  • Android WebView控件捕獲用戶輸入的信息

    Android WebView控件捕獲用戶輸入的信息

    這篇文章主要為大家詳細(xì)介紹了Android WebView控件捕獲用戶輸入的信息,感興趣的小伙伴們可以參考一下
    2016-02-02
  • Android  回調(diào)詳解及簡單實(shí)例

    Android 回調(diào)詳解及簡單實(shí)例

    這篇文章主要介紹了Android 回調(diào)詳解及簡單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • Android自定義ViewGroup實(shí)現(xiàn)標(biāo)簽流效果

    Android自定義ViewGroup實(shí)現(xiàn)標(biāo)簽流效果

    這篇文章主要為大家詳細(xì)介紹了Android自定義ViewGroup實(shí)現(xiàn)標(biāo)簽流效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06

最新評論