iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >Android学习之介绍Binder的简单使用
  • 588
分享到

Android学习之介绍Binder的简单使用

android学习binderAndroid 2022-06-06 05:06:09 588人浏览 薄情痞子
摘要

前言 最近因为公司项目需求,需要远程调度启动客户端输入法输入内容。 这就是大致的需求流程,这篇首先讲远程与服务控制端通讯。首先控制服务端定义好一个Service,且在Ser

前言

最近因为公司项目需求,需要远程调度启动客户端输入法输入内容。


这就是大致的需求流程,这篇首先讲远程与服务控制端通讯。首先控制服务端定义好一个Service,且在ServiceManager注册添加服务。

在这里我讲解远程端与服务控制端通讯(主要通过C++往ServiceManager注册服务)。

首先我们得获取到服务控制端注册在ServiceManager的服务IBinder对象,通过Java反射机制获得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();//打印系统所提供的所有服务
 }
 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
 
 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对象作用是跨进程,举个例子,输入法程序是怎么和应用编辑框通讯的呢?怎么通过什么控制输入法弹起隐藏的呢。也是通过这个IBinder来通讯的,不信你翻翻源码,这里不做详细介绍。

而服务控制端则是由C++层注入服务:


class IServiceManager : public IInterface
{
public:
 DECLARE_META_INTERFACE(ServiceManager);
 
 virtual sp<IBinder> getService( const String16& name) const = 0;
 
 virtual sp<IBinder> checkService( const String16& name) const = 0;
 
 virtual status_t addService( const String16& name,
   const sp<IBinder>& service,
   bool allowIsolated = false) = 0;
 
 virtual Vector<String16> listServices() = 0;
 enum {
 GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
 CHECK_SERVICE_TRANSACTION,
 ADD_SERVICE_TRANSACTION,
 LIST_SERVICES_TRANSACTION,
 };
};

//上面c++层注册服务提供一个IBinder接口子类,需要实现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对象与之通讯了,这里我只讲个例子:

当远程端设备输入法激活的时候,我将传递输入法输入类型和输入法展示的多功能键传递给服务控制端。


 //当输入法被激活的时候,会调用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);
 }
 }
//这里我将两个int参数写入到Parce对象中开始进行通讯

 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方法进行通讯。


//code必须双方定义好,否则接收数据无法正常,
//第一个是我们装载的序列化数据,
//第二我们可以直接传个对象,最好一个是需要返回结果的标识,
//0代表需要返回内容,FLAG_ONEWAY单方面无需返回结果的标识
public boolean transact(int code, Parcel data, Parcel reply, int flags)
 throws RemoteException;

当我们调用了

ibinder.transact(int,parce,parce,int)
方法,这是注册的服务中的IBinder对象的
onTransact(int,parce,parce,int)
方法就会被响应,这样我们就实现了远程端跟服务控制端通讯了。

到了这里,有个问题,服务控制端接收到客户端输入的内容咋办,怎通知远程端输入法输入内容到编辑框中呢。

其实也很简单,我们只需要在远程端输入法程序实现一个Ibinder对象,传递给服务控制端,这样就可以实现,具体怎么传递了?


//首先我们得让远程输入法程序拥有属于自己的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文件的内容一样,aidl其实就是Android自己给我写好的ibinder代码一样。

这样我们就可以在获取到服务控制端ibinder对象中写入我们自己ibinder对象,传递过去让他通过transact方法来与输入法程序ibinder对象通讯了。


 //Parce类中提供了这样的一个方法,就是用于写入ibinder对象的。
 public final void writeStrongBinder(IBinder val) {
 nativeWriteStrongBinder(mNativePtr, val);
 }

这样我们就可以在InputBinder类中来处理返回的数据了。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

您可能感兴趣的文章:Android通过继承Binder类实现多进程通信Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路Android深入浅出之Binder机制Android进程间通信(IPC)机制Binder简要介绍理解Android系统Binder机制Android4.1中BinderService用法实例分析android IPC之binder通信机制Android中Binder详细学习心得


--结束END--

本文标题: Android学习之介绍Binder的简单使用

本文链接: https://www.lsjlt.com/news/22778.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 【Android】Binder(一)Binder的介绍和AIDL使用Binder的实例
    Binder介绍 Android 中的 Binder 是一个进程间通信机制,它允许不同进程之间相互调用方法和传递数据。Binder 主要用于实现系统服务和应用程序之间的通信,以及实现 IPC(Inte...
    99+
    2023-09-03
    android binder 网络
  • Android学习之Broadcast的简单使用
    本文实例为大家分享了Android学习之Broadcast的使用方法,供大家参考,具体内容如下实现开机启动提示网络的广播package com.example.luobo.broadcasttest;import android.conte...
    99+
    2023-05-30
    android broadcast roi
  • Android学习之菜单的使用方法
    本文实例为大家分享了Android学习之菜单使用的具体代码,供大家参考,具体内容如下 Android中菜单包含上下文菜单和选项菜单两种类型。 使用统一的菜单类来管理菜单: Menu、...
    99+
    2024-04-02
  • python使用sqlite简单介绍
    python连接sqlite非常简单,基本步骤如下: 用sqlite3.connect创建数据库连接,假设连接对象为conn 如果该数据库操作不需要返回结果,就直接用conn.execute查询,如建表、删表、添加、修改删除数据...
    99+
    2023-01-31
    简单 python sqlite
  • Java新手学习之IO流的简单使用
    目录前言IO流1、基本概念 2、IO流分类 3、File3.1File基本概念3.2创建文本3.3创建目录3.4判断、读取和删除4、字节流 4.1字节流...
    99+
    2024-04-02
  • Micronaut框架的简单使用介绍
    目录什么是Micronaut主要特点入门依赖注入构建HTTP服务器阻塞HTTP反应式IO构建HTTP客户端声明性HTTP客户端编程HTTP客户端Micronaut客户端联合项目特征现...
    99+
    2024-04-02
  • Spring注解之@Import的简单介绍
    目录普通类ImportSelector实现类DeferredImportSelector实现类附:@Import相关源码解析总结 @Import可以导入以下几种种类: 普通...
    99+
    2022-12-23
    spring注解import @import注解 spring import注解
  • Java - JWT的简单介绍和使用
    Java - JWT的简单介绍和使用 前言一. JWT 基础知识1.1 session 案例测试1.2 JWT 结构1.2.1 Header1.2.2 Payload1.2.3 Signatu...
    99+
    2023-10-27
    java 开发语言 spring boot
  • Android 之 ViewPager 的简单使用
    本节引言: 本节带来的是Android 3.0后引入的一个UI控件——ViewPager(视图滑动切换工具),实在想不到 如何来称呼这个控件,他的大概功能:通过手势滑动可以完成View的切换,一般是用来做APP 的引导页或者实现图片轮播...
    99+
    2023-09-13
    android 动画
  • C# FileStream简单介绍和使用
    FileStream 是 C# 中用于操作文件的类,它提供了一种以字节为单位读取和写入文件的功能。使用 FileStream,可以实...
    99+
    2023-08-08
    C#
  • 简单介绍如何使用GitHub
    在现代互联网社会中,程序员们都离不开GitHub这个开源代码仓库。它不仅可以用于托管代码,还可以与其他合作者共同合作开发同一项目。但是,对于初次使用GitHub的人来说,可能会感到有些困惑。在本文中,我们将介绍如何使用GitHub。首先,需...
    99+
    2023-10-22
  • 【java学习】EasyExcel的简单使用
    EasyExcel的简单使用 前言Excel读1.实体类2.读监听器与测试类3.输出结果 Excel写1.实体类2.写入Excel的测试类3.输出结果 填充Excel1.Excel模板...
    99+
    2023-10-03
    java 学习
  • MinIO的介绍以及简单的使用
    什么是MinIO MinIO是在GUN Affero通用公共许可证 v3.0 下发布的高性能对象存储.他与AmazonS3云存储服务API兼容.使用MinIO为机器学习,分析和应用程序数据工作负载构建高性能基础架构. MinIO是一个高...
    99+
    2023-10-26
    java Powered by 金山文档
  • python学习-ansible简单使用
    一、介绍Ansible 一种集成 IT 系统的配置管理、应用部署、执行特定任务的开源平台,是 AnsibleWorks 公司名下的项目,该公司由 Cobbler 及 Func 的作者于 2012 年创建成立。Ansible 基于 Pytho...
    99+
    2023-01-31
    简单 python ansible
  • Python运算符的使用简单介绍
    目录1、算术运算符2、赋值运算符3、比较运算符4、逻辑运算符5、位运算符6、运算符优先级和结合性1、算术运算符 Python 中常用运算符: 运算符说明实例结果+加22.4 + 15...
    99+
    2024-04-02
  • Python变量定义的简单使用介绍
    目录1、变量的定义2、变量的简单使用3、类型转换1、变量的定义 定义变量语法格式: variable_name = variable_name variable_name表示变量名;...
    99+
    2024-04-02
  • python数学建模之Numpy 应用介绍与Pandas学习
    目录Numpy学习1 Numpy 介绍与应用1-1Numpy是什么2 NumPy Ndarray 对象3 Numpy 数据类型4 Numpy 数组属性Pandas学习1 pandas...
    99+
    2024-04-02
  • Android学习之BottomSheetDialog组件的使用
    目录基本介绍基础使用其他功能实现圆角样式实现去弹窗外部遮罩阴影关闭触发设置列表视图使用基本介绍 BottomSheetDialog是底部操作控件,可在屏幕底部创建一个支持滑动关闭视图...
    99+
    2024-04-02
  • Android资源管理框架(Asset Manager)简要介绍和学习计划
    Android资源管理框架(Asset Manager)是Android系统中的一个重要组件,用于管理应用程序中的资源文件。它可以用...
    99+
    2023-09-28
    Android
  • jQuery中bind的用法简单介绍
    jQuery中的bind()方法用于将一个处理函数绑定到指定的元素上,该处理函数将在特定事件触发时被调用。bind()方法的基本语法如下:```javascript$(selector).bind(event, data, handle...
    99+
    2023-08-09
    jQuery
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作