【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作用一样,都可以进行进程间通讯.它是基于消 ...
随机推荐
- Mongo-文档主键-ObjectId
文档主键 文档主键时 _id,如果插入文档时,没有传入则自动生产ObjectId 作为文档主键 文档主键要求在集合中唯一 文档主键可以时另一个文档,被当作字符串对象处理 ObjectId对象 获取文档 ...
- [转帖]AF_UNIX和AF_INET
https://www.cnblogs.com/shangerzhong/p/9153737.html family参数代表地址家族,比较常用的为AF_INET或AF_UNIX.AF_UNIX用于同一 ...
- [转帖]MinIO Client(mc)完全指南
https://www.cnblogs.com/lvzhenjiang/p/14944821.html 目录 一.获取MinIO Client(mc) 1.1 docker版 1.2 Homebrew ...
- Nginx双层域名时 iframe嵌入/跳转页面的处理过程
Nginx双层域名时 iframe嵌入/跳转页面的处理过程 背景 两年前在上一家公司内遇到一个Nginx的问题 当时的场景是 双层nginx代理时(一层域名侧, 一层拆分微服务的网关层) 程序里面会打 ...
- [转帖]Springboot配置kafka用户名密码
华为云开发者联盟 Springboot配置kafka用户名密码 Springboot配置kafka用户名密码 SpringBoot配置kafka用户名密码 Springboot配置kafka用户名密码 ...
- [转帖]Linux 监测服务心跳、服务重启策略
文章目录 前言 背景 一.curl服务可用验证 二.服务探测脚本 三.配置系统定时任务 四.Linux特殊字符转义 总结 前言 请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i. 提示:以下是 ...
- 当你对 redis 说你中意的女孩是 Mia
作者:京东科技 周新智 一.Redis 众所周知,Redis = Remote Dictionary Server,即远程字典服务. 是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久 ...
- Spring源码之XML文件中Bean标签的解析1
读取XML文件,创建对象 xml文件里包含Bean的信息,为了避免多次IO,需要一次性读取xml文件中所有bean信息,加入到Spring工厂. 读取配置文件 new ClassPathResourc ...
- .net5发布到Linux指南
目录 Aspnetcore api 服务发布指南 一. 搭建nginx服务器 下载安装gcc编译库 下载安装pcre正则表达式库 下载安装openssl安全加密库 下载安装zlib解压库 下载解压并编 ...
- 强化学习基础篇[3]:DQN、Actor-Critic详细讲解
强化学习基础篇[3]:DQN.Actor-Critic详细讲解 1.DQN详解 1.1 DQN网络概述及其创新点 在之前的内容中,我们讲解了Q-learning和Sarsa算法.在这两个算法中,需要用 ...