【Android】使用Binder实现进程间通讯简单案例
1 前言
使用AIDL实现进程间通讯简单案例 和 使用AIDL实现进程间传递对象案例 中介绍了使用 AIDL 进行进程间通讯,文中提到在编写完 aidl 文件(如:IMessageManager.aidl)并 Make Buidl 后,会生成一个接口(如:IMessageManager.java),接口中包含一个静态抽象内部类 Stub,Stub 中又包含一个静态内部类 Proxy,Stub 和 Proxy 都实现了此接口,同时 Stub 继承了 Binder 类。本文将从 IMessageManager 接口中剥离 Stub(用于服务端) 和 Proxy(用于客户端),使读者更深刻的理解 AIDL 和 Binder,如下。

说明:左边 Stub 为抽象类,无需重写 sendMsg、getMsg,右边 Stub 为具体类,需要重写 sendMsg、getMsg。
(1)AIDL中生成服务端与客户端
服务端:IMessageManager.Stub mBind = new MessageManager.Stub()
客户端:mMessageManager = IMessageManager.Stub.asInterface(service)(service 是服务端传过来的Binder,即 mBind)
(2)本文中生成服务端与客户端
服务端:Stub mBind = new Stub()
客户端:mMessageManager = new Proxy(service)(service 是服务端传过来的Binder,即 mBind)
本文全部代码见→使用Binder实现进程间通讯简单案例
2 Binder 简介
Binder 翻译即粘合剂,是客户端和服务端沟通的桥梁,用于进程建通讯。Binder 的主要属性和方法如下:

在 transact 方法中调用了 onTransact,如下:
public final boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
使用 Binder 进行进程间通讯时,需要做以下工作:
(1)Stub 类(服务端创建 Binder的子类)
- Stub extends Binder implements IMessageManager
- 构造方法中调用 this.attachInterface(this, DESCRIPTOR)
- asBinder 方法返回 this
- 重写 IMessageManager 接口中的方法
- 重写 Binder 的 onTransact 方法
(2)Proxy 类(客户端接受 Binder,并对其进行封装)
- Proxy implements IMessageManager
- 构造方法接受 Binder:mRemote = remote
- asBinder 方法返回 mRemote
- 重写 IMessageManager 接口中的方法,调用 mRemote.transact(code, data, reply, 0)
3 项目结构

4 服务端 binder_S 代码
IMessagManager.java
package com.zhyan8.binder_s;
import android.os.IInterface;
import android.os.RemoteException;
public interface IMessageManager extends IInterface {
public void sendMsg(String msg) throws RemoteException;
public String getMsg() throws RemoteException;
}
Stub.java
package com.zhyan8.binder_s;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
public class Stub extends Binder implements IMessageManager {
private final String DESCRIPTOR = "com.yyy.binder";
private final int TRANSACTION_sendMsg = IBinder.FIRST_CALL_TRANSACTION;
private final int TRANSACTION_getMsg = IBinder.FIRST_CALL_TRANSACTION + 1;
public Stub(){
this.attachInterface(this, DESCRIPTOR);
}
@Override
public IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case TRANSACTION_sendMsg:
data.enforceInterface(DESCRIPTOR);
String msg = data.readString();
this.sendMsg(msg);
reply.writeNoException();
return true;
case TRANSACTION_getMsg:
data.enforceInterface(DESCRIPTOR);
String _result = this.getMsg();
reply.writeNoException();
reply.writeString(_result);
return true;
}
return super.onTransact(code, data, reply, flags);
}
@Override
public void sendMsg(String msg) throws RemoteException {
Log.d("MyService", "客户端发来消息: " + msg);
System.out.println(msg);
}
@Override
public String getMsg() throws RemoteException {
return "abcde"; //客户端待接收的消息
}
}
注意:DESCRIPTOR 取值必须和 Proxy 中一致。
MyService.java
package com.zhyan8.binder_s;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return mBind;
}
Stub mBind = new Stub();
}
在 AndroidManifest.xml 中配置服务如下:
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.xxx.binder"/>
</intent-filter>
</service>
MainActivity.java
package com.zhyan8.binder_s;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
5 客户端 binder_C 代码
IMessagManager.java 同第 4 节。
Proxy.java
package com.zhyan8.binder_c;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
public class Proxy implements IMessageManager {
private IBinder mRemote;
private final String DESCRIPTOR = "com.yyy.binder";
private final int TRANSACTION_sendMsg = IBinder.FIRST_CALL_TRANSACTION;
private final int TRANSACTION_getMsg = IBinder.FIRST_CALL_TRANSACTION + 1;
Proxy(IBinder remote) {
mRemote = remote;
}
@Override
public IBinder asBinder() {
return mRemote;
}
@Override
public void sendMsg(String msg) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(DESCRIPTOR);
data.writeString(msg);
mRemote.transact(TRANSACTION_sendMsg, data, reply, 0);
reply.readException();
} finally {
reply.recycle();
data.recycle();
}
}
@Override
public String getMsg() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
String result;
try {
data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(TRANSACTION_getMsg, data, reply, 0);
reply.readException();
result = reply.readString();
} finally {
reply.recycle();
data.recycle();
}
return result;
}
}
注意:DESCRIPTOR 取值必须和 Stub 中一致。
MainActivity.java
package com.zhyan8.binder_c;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private Proxy mMessageManager;
private EditText et_msg;
private Button btn_send;
private TextView tv_msg;
private Button btn_recv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
public void init() {
et_msg = (EditText) findViewById(R.id.et_msg);
btn_send = (Button) findViewById(R.id.btn_send);
tv_msg = (TextView) findViewById(R.id.tv_msg);
btn_recv = (Button) findViewById(R.id.btn_recv);
btn_send.setOnClickListener(cl);
btn_recv.setOnClickListener(cl);
}
View.OnClickListener cl = new View.OnClickListener(){
@Override
public void onClick(View v) {
if (v.getId()==R.id.btn_send) {
String str = et_msg.getText().toString();
sendMsg(str);
}else if(v.getId()==R.id.btn_recv) {
String str = getMsg();
tv_msg.setText(str);
}
}
};
private void sendMsg(String str){
if (mMessageManager==null) {
attemptToBindService();
}
try {
mMessageManager.sendMsg(str);
} catch (RemoteException e) {
e.printStackTrace();
}
}
private String getMsg(){
if (mMessageManager==null) {
attemptToBindService();
}
try {
String str = mMessageManager.getMsg();
return str;
} catch (RemoteException e) {
e.printStackTrace();
}
return "";
}
private void attemptToBindService() {
Intent intent = new Intent();
intent.setAction("com.xxx.binder");
intent.setPackage("com.zhyan8.binder_s");
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMessageManager = new Proxy(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mMessageManager = null;
}
};
@Override
protected void onStart() {
super.onStart();
if (mMessageManager==null) {
attemptToBindService();
}
}
@Override
protected void onStop() {
super.onStop();
if (mMessageManager!=null) {
unbindService(conn);
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:id="@+id/et_msg"
android:layout_width="match_parent"
android:layout_height="100dp"
android:textSize="30sp"
android:background="#ffcc66"/>
<Button
android:id="@+id/btn_send"
android:layout_width="match_parent"
android:layout_height="80dp"
android:text="发送"
android:textSize="30sp"
android:layout_marginTop="30dp"/>
<TextView
android:id="@+id/tv_msg"
android:layout_width="match_parent"
android:layout_height="100dp"
android:textSize="30sp"
android:background="#ffcc66"
android:layout_marginTop="50dp"/>
<Button
android:id="@+id/btn_recv"
android:layout_width="match_parent"
android:layout_height="80dp"
android:text="接收"
android:textSize="30sp"
android:layout_marginTop="30dp"/>
</LinearLayout>
界面如下:

6 效果展示
(1)发送消息
在 EditView 中输入【asdfg】,点击【发送】按钮,在服务端可以收到发送的消息,如下:

(2)接收消息
点击【接收】按钮,客户端 binder_C 界面可以看到服务端 binder_S 传过来的字符串【abcde】,如下:

声明:本文转自【Android】使用Binder实现进程间通讯简单案例
【Android】使用Binder实现进程间通讯简单案例的更多相关文章
- 一篇文章了解相见恨晚的 Android Binder 进程间通讯机制【转】
本文转载自:https://blog.csdn.net/freekiteyu/article/details/70082302 Android-Binder进程间通讯机制 概述 最近在学习Binder ...
- Android Binder 进程间通讯机制梳理
什么是 Binder ? Binder是Android系统中进程间通讯(IPC)的一种方式,也是Android系统中最重要的特性之一.Binder的设计采用了面向对象的思想,在Binder通信模型的四 ...
- android 进程间通信 messenger 是什么 binder 跟 aidl 区别 intent 进程间 通讯? android 消息机制 进程间 android 进程间 可以用 handler么 messenger 与 handler 机制 messenger 机制 是不是 就是 handler 机制 或 , 是不是就是 消息机制 android messenge
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha messenger 是什么 binder 跟 aidl 区别 intent 进程间 通讯 ...
- Android进程间通讯
最近研究了一下Android进程间通讯,原来只是会用,但是只是会用是不行滴,就来研究一下. 刚开始看的时候,我的头是这么大,看了一夜的时候,头就变成这样了,,吓得宝宝赶紧上床休息了,. 先喝喝茶讲个故 ...
- Android进程间通讯之messenger
这两天在看binder,无意间在文档看到messenger这么个东西,感觉这个东西还挺有意思的,给大家分享一下. 平时一说进程间通讯,大家都会想到AIDL,其实messenger和AIDL作用一样,都 ...
- Android查缺补漏(IPC篇)-- 进程间通讯基础知识热身
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8479282.html 在Android中进程间通信是比较难的一部分,同时又非常 ...
- Android查缺补漏(IPC篇)-- Bundle、文件共享、ContentProvider、Messenger四种进程间通讯介绍
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8387752.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(IPC篇)-- 进程间通讯之AIDL详解
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android AIDL 进行进程间通讯(IPC)
编写AIDL文件时,需要注意: 1.接口名和aidl文件名相同. 2.接口和方法前不用加访问权限修饰符 (public.private.protected等,也不能用final.static). 3. ...
- Android进阶笔记04:Android进程间通讯(IPC)之Messenger
一. Android进程间通讯之Messenger 的引入 (1)引言: 平时一说进程间通讯,大家都会想到AIDL,其实messenger和AIDL作用一样,都可以进行进程间通讯.它是基于消 ...
随机推荐
- C++模板显示指定类型时使用引用遇到的问题
1.问题 这里我想让模板函数接收int和char类型的参数,并进行相加,显示指定参数类型为int. 第一个调用理论上会自动将char类型强转成int类型,后进行相加: 第二个调用理论上会自动将int类 ...
- .Net 使用 MongoDB
1.安装nuget包 MongoDB.Driver 2.简单代码 using MongoDB.Bson; using MongoDB.Driver; using System.Buffers; usi ...
- 《OnJava》——11内部类
内部类 利用内部类,可以将逻辑上存在关联的类组织在一起,而且可以控制一个类在另一个类中的可见性. 内部类和组合不同,内部类是一种代码隐藏机制:将代码放在其他类的内部. 11.1 创建内部类 创建内部类 ...
- [转帖]s3fs
https://github.com/s3fs-fuse/s3fs-fuse s3fs allows Linux, macOS, and FreeBSD to mount an S3 bucket v ...
- [转帖]谈谈对K8S CNI、CRI和CSI插件的理解
K8S的设计初衷就是支持可插拔架构,解决PaaS平台不好用.不能用.需要定制化等问题,K8S集成了插件.附加组件.服务和接口来扩展平台的核心功能.附加组件被定义为与环境的其他部分无缝集成的组件,提供类 ...
- [转帖]jmeter线程组与循环次数的区别
在压测的时候,有些接口需要携带登录信息,但是我们只想登录一次,然后其他接口进行多用户压测,此时你会怎么办?用仅一次控制器实现吗?下面我们来看看用仅一次控制器能不能实现 压测时jmeter中的线程数是模 ...
- [转帖]读懂什么是RDMA
https://blog.csdn.net/tony_vip?type=blog 一.什么是RDMA1.RDMA主要体现 2.如何理解RDMA和TCP技术的区别?3.使用RDMA的好处包括: ...
- [转帖]redis进程绑定指定的CPU核
文章系转载,便于分类和归纳,源文地址:https://blog.csdn.net/youlinhuanyan/article/details/99671878 1)查看某服务的pid $ ps -au ...
- [转帖]自动化运维:一键自动化脚本-shell
https://www.cnblogs.com/luoahong/articles/8456203.html shell函数 1.分别在服务器和客户端上创建www用户 1 2 useradd www ...
- ESXi查看底层存储磁盘厂商型号的方式与方法
ESXi查看底层存储磁盘厂商型号的方式与方法 背景 公司一台过保的服务器出现了磁盘告警 Vendor不太靠谱. 过保的机器就不管了 不买他们的服务器也不说一下是啥硬盘. 想自己替换,需要先获取磁盘的型 ...