1.具体代码:

服务端实现:

public class IPCService extends Service {

    private static final String DESCRIPTOR = "IPCService";
private final String[] names = { "B神", "艹神", "基神", "J神", "翔神" };
private MyBinder mBinder = new MyBinder(); private class MyBinder extends Binder {
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case 0x001: {
data.enforceInterface(DESCRIPTOR);
int num = data.readInt();
reply.writeNoException();
reply.writeString(names[num]);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
} @Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}

可以看到onTransact有四个参数 
code , data ,replay , flags

  • code 是一个整形的唯一标识,用于区分执行哪个方法,客户端会传递此参数,告诉服务端执行哪个方法;
  • data客户端传递过来的参数;
  • replay服务器返回回去的值;
  • flags标明是否有返回值,0为有(双向),1为没有(单向)。

客户端实现:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private EditText edit_num;
private Button btn_query;
private TextView txt_result;
private IBinder mIBinder;
private ServiceConnection PersonConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mIBinder = null;
} @Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIBinder = service;
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindViews(); // 绑定远程Service
Intent service = new Intent("android.intent.action.IPCService");
service.setPackage("com.jay.ipcserver");
bindService(service, PersonConnection, BIND_AUTO_CREATE);
btn_query.setOnClickListener(this);
} private void bindViews() {
edit_num = (EditText) findViewById(R.id.edit_num);
btn_query = (Button) findViewById(R.id.btn_query);
txt_result = (TextView) findViewById(R.id.txt_result);
} @Override
public void onClick(View v) {
int num = Integer.parseInt(edit_num.getText().toString());
if (mIBinder == null) {
Toast.makeText(this, "未连接服务端或服务端被异常杀死", Toast.LENGTH_SHORT).show();
} else {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
String _result = null;
try {
_data.writeInterfaceToken("IPCService");
_data.writeInt(num);
mIBinder.transact(0x001, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
txt_result.setText(_result);
edit_num.setText("");
} catch (RemoteException e) {
e.printStackTrace();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
}

2.transact和onTransact的区别

谈transact 和onTransact需要先聊聊iBinder

IBinder是什么呢?首先要明白,Android的远程调用(就是跨进程调用)就是通过IBinder实现的,下面是对android开发文档的翻译。

  IBinder是远程对象的基本接口,是为高性能而设计的轻量级远程调用机制的核心部分。但它不仅用于远程调用,也用于进程内调用。这个接口定义了与远程对象交互的协议。不要直接实现这个接口,而应该从Binder派生。

  IBinder的主要API是transact(),与它对应另一方法是Binder.onTransact()。第一个方法使你可以向远端的IBinder对象发送发出调用,第二个方法使你自己的远程对象能够响应接收到的调用。IBinder的API都是同步执行的,比如transact()直到对方的Binder.onTransact()方法调用完成后才返回。调用发生在进程内时无疑是这样的,而在进程间时,在IPC的帮助下,也是同样的效果。
  通过transact()发送的数据是Parcel,Parcel是一种一般的缓冲区,除了有数据外还带有一些描述它内容的元数据。元数据用于管理IBinder对象的引用,这样就能在缓冲区从一个进程移动到另一个进程时保存这些引用。这样就保证了当一个IBinder被写入到Parcel并发送到另一个进程中,如果另一个进程把同一个IBinder的引用回发到原来的进程,那么这个原来的进程就能接收到发出的那个IBinder的引用。这种机制使IBinder和Binder像唯一标志符那样在进程间管理。
  系统为每个进程维护一个存放交互线程的线程池。这些交互线程用于派送所有从另外进程发来的IPC调用。例如:当一个IPC从进程A发到进程B,A中那个发出调用的线程(这个应该不在线程池中)就阻塞在transact()中了。进程B中的交互线程池中的一个线程接收了这个调用,它调用Binder.onTransact(),完成后用一个Parcel来做为结果返回。然后进程A中的那个等待的线程在收到返回的Parcel后得以继续执行。实际上,另一个进程看起来就像是当前进程的一个线程,但不是当前进程创建的。
  Binder机制还支持进程间的递归调用。例如,进程A执行自己的IBinder的transact()调用进程B的Binder,而进程B在其Binder.onTransact()中又用transact()向进程A发起调用,那么进程A在等待它发出的调用返回的同时,还会用Binder.onTransact()响应进程B的transact()。总之Binder造成的结果就是让我们感觉到跨进程的调用与进程内的调用没什么区别。
  当操作远程对象时,你经常需要查看它们是否有效,有三种方法可以使用:
  1 transact()方法将在IBinder所在的进程不存在时抛出RemoteException异常。
  2 如果目标进程不存在,那么调用pingBinder()时返回false。
  3 可以用linkToDeath()方法向IBinder注册一个IBinder.DeathRecipient,在IBinder代表的进程退出时被调用。
  要实现IBinder来支持远程调用,应从Binder类派生一个类。Binder实现了IBinder接口。但是一般不需要直接实现此类,而是跟据你的需要由开发包中的工具生成,这个工具叫AIDL。你通过AIDL语言定义远程对象的方法,然后用AIDL工具生成Binder的派生类,然后就可使用之。然而,可是,但是,当然,你也可以直接从Binder类派生以实现自定义的RPC调用,或只是实例化一个原始的Binder对象直接作为进程间共享的令牌来使用。

  

  

直接通过Binder的onTransact完成跨进程通信的更多相关文章

  1. 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇

    前言 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一.Android系统的运行由大量相互独立的进程相互协助来完成的,所以Android进程间通信问题,是做好Andro ...

  2. 图文详解 Android Binder跨进程通信机制 原理

    图文详解 Android Binder跨进程通信机制 原理 目录 目录 1. Binder到底是什么? 中文即 粘合剂,意思为粘合了两个不同的进程 网上有很多对Binder的定义,但都说不清楚:Bin ...

  3. 跨进程通信之Messenger

    1.简介 Messenger,顾名思义即为信使,通过它可以在不同进程中传递Message对象,通过在Message中放入我们需要的入局,就可以轻松实现数据的跨进程传递了.Messenger是一种轻量级 ...

  4. 不依赖AIDL的跨进程通信

    http://blog.csdn.net/lmj623565791/article/details/38461079 如果知道AIDL和binder的原理,可以简单写一个不依赖AIDL的跨进程通信 不 ...

  5. 详解 CmProcess 跨进程通信的实现

    CmProcess 是 Android 一个跨进程通信框架,整体代码比较简单,总共 20 多个类,能够很好的便于我们去了解跨进程实现的原理. 个人猜测 CmProcess 也是借鉴了 VirtualA ...

  6. Android-Messenger跨进程通信

    http://blog.csdn.net/lmj623565791/article/details/47017485 一.概述 我们可以在客户端发送一个Message给服务端,在服务端的handler ...

  7. android 远程Service以及AIDL的跨进程通信

    在Android中,Service是运行在主线程中的,如果在Service中处理一些耗时的操作,就会导致程序出现ANR. 但如果将本地的Service转换成一个远程的Service,就不会出现这样的问 ...

  8. 【朝花夕拾】跨进程通信,你只知道AIDL,就OUT了

    一.前言 提起跨进程通信,大多数人首先会想到AIDL.我们知道,用AIDL来实现跨进程通信,需要在客户端和服务端都添加上aidl文件,并在服务端的Service中实现aidl对应的接口.如果还需要服务 ...

  9. Android随笔之——跨进程通信(一) Activity篇

    在Android应用开发中,我们会碰到跨进程通信的情况,例如:你用QQ通讯录打电话的时候会调用系统的拨号应用.某些新闻客户端可以将新闻分享到QQ.微信等应用,这些都是跨进程通信的情况.简而言之,就是一 ...

随机推荐

  1. mongo 让字段自增或自减

    查询语句 db.getCollection("A表").update( { id: 1 }, { $inc: { pid: 1} } ) 作用:根据条件让A表中的pid字段自增1 ...

  2. odoo开发笔记 -- div标签代替odoo button写法

    odoo开发笔记 -- div标签代替odoo button写法 并调用自定义js <footer> <div id="confirm_request_cloud_repo ...

  3. mysql中计算日期整数差

    TIMESTAMPDIFF 语法: TIMESTAMPDIFF(interval,datetime_expr1,datetime_expr2) : 返回日期或日期时间表达式datetime_expr1 ...

  4. go等待N个线程完成操作总结

    第一种,基于原生带缓存的channel package main import "fmt" func main() { done := make(chan int, 10) for ...

  5. SOAP系列目录

    1.协议分析 2.WebService.WCF介绍 3.HttpClientHelper实现webservice调用 4.SoapCore介绍

  6. datatables 配套bootstrap3样式使用小结(1)

    今天介绍汇总一下datatables. 网址: www.datatables.net 公司CMS内容资讯站的后台管理界面用了大量的table来管理数据,试用了之后,感觉挺不错,推荐一下. 先上一个基本 ...

  7. Jenkins持续集成学习-搭建jenkins问题汇总

    目录 Jenkins持续集成学习5-搭建jenkins问题汇总 目录 前言 问题列表 nuget还原包问题 编译问题 SVN更新问题 参考文档 Jenkins持续集成学习5-搭建jenkins问题汇总 ...

  8. retry重试常见场景及实现

    当我们的代码是有访问网络相关的操作时,比如http请求或者访问远程数据库,经常可能会发生一些错误,有些错误可能重新去发送请求就会成功,本文分析常见可能需要重试的场景,并最后给出python代码实现. ...

  9. 了解golang的可变参数(... parameters),这一篇就够了

    在实际开发中,总有一些函数的参数个数是在编码过程中无法确定的,比如我们最常用的fmt.Printf和fmt.Println: fmt.Printf("一共有%v行%v列\n", r ...

  10. Spring Boot入门(11)实现文件下载功能

      在这篇博客中,我们将展示如何在Spring Boot中实现文件的下载功能.   还是遵循笔者写博客的一贯风格,简单又不失详细,实用又能让你学会.   本次建立的Spring Boot项目的主要功能 ...