【Android】使用Binder实现进程间传递对象案例
1 前言
使用AIDL实现进程间通讯简单案例 和 使用AIDL实现进程间传递对象案例 中介绍了使用 AIDL 进行进程间通讯,其本质仍然是Binder,aidl 文件对应生成的接口中,将服务端调用的抽象类(Stub)和客户端调用的代理类(Proxy)糅合在一个 java 文件中,使得新手读起来云里雾里。使用Binder实现进程间通讯简单案例 中试图将生成的接口拆分为2个类(Stub 和 Proxy),分别布置在服务端和客户端,能够帮助读者更好地理解 AIDL 和 Binder。本文将延续 使用Binder实现进程间通讯简单案例 中的思路,介绍使用Binder 实现进程间传输对象。
本文全部代码见→使用Binder实现进程间传递对象案例
2 项目结构

3 服务端 aidl_s 代码
User.java
package com.zhyan8.binder_c;
import android.os.Parcel;
import android.os.Parcelable;
public class User implements Parcelable{
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
protected User(Parcel in) {
name = in.readString();
age = in.readInt();
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "User{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
IMessageManager.java
package com.zhyan8.binder_c;
import android.os.IInterface;
import android.os.RemoteException;
public interface IMessageManager extends IInterface {
public void sendMsg(User user) throws RemoteException;
public User 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 {
User user;
switch (code) {
case TRANSACTION_sendMsg:
data.enforceInterface(DESCRIPTOR);
user = User.CREATOR.createFromParcel(data);
this.sendMsg(user);
reply.writeNoException();
return true;
case TRANSACTION_getMsg:
data.enforceInterface(DESCRIPTOR);
user = this.getMsg();
reply.writeNoException();
user.writeToParcel(reply, 1);
return true;
}
return super.onTransact(code, data, reply, flags);
}
@Override
public void sendMsg(User user) throws RemoteException {
Log.d("MyService", "客户端发来消息: " + user.toString());
System.out.println(user.toString());
}
@Override
public User getMsg() throws RemoteException {
return new User("小红", 23); //客户端待接收的消息
}
}
注意: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 文件中 application 节点下注册 service,如下。
<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);
}
}
4 客户端 aidl_c 代码
User.java 和 IMessageManager.java 同第3节。
Proxy.java
package com.zhyan8.binder_c;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
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(User user) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(DESCRIPTOR);
user.writeToParcel(data, 0);
mRemote.transact(TRANSACTION_sendMsg, data, reply, 0);
reply.readException();
} finally {
reply.recycle();
data.recycle();
}
}
@Override
public User getMsg() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
User user;
try {
data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(TRANSACTION_getMsg, data, reply, 0);
reply.readException();
user = User.CREATOR.createFromParcel(reply);
} finally {
reply.recycle();
data.recycle();
}
return user;
}
}
注意:DESCRIPTOR 取值必须和 Stub 中一致。
MainActivity.java
package com.zhyan8.binder_c;
import android.app.Activity;
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.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private IMessageManager mMessageManager;
private EditText et_name;
private EditText et_age;
private Button btn_send;
private TextView tv_name;
private TextView tv_age;
private Button btn_recv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
public void init() {
et_name = (EditText) findViewById(R.id.et_name);
et_age = (EditText) findViewById(R.id.et_age);
btn_send = (Button) findViewById(R.id.btn_send);
tv_name = (TextView) findViewById(R.id.tv_name);
tv_age = (TextView) findViewById(R.id.tv_age);
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) {
hideInputMethod(MainActivity.this, v); //关闭输入法
if (v.getId()==R.id.btn_send) {
try {
String name_t = et_name.getText().toString();
int age_t = Integer.parseInt(et_age.getText().toString());
User user = new User(name_t, age_t);
sendMsg(user);
} catch (Exception e) {
Toast.makeText(MainActivity.this, "请输入姓名和年龄", Toast.LENGTH_SHORT).show();
}
}else if(v.getId()==R.id.btn_recv) {
User user = getMsg();
tv_name.setText(user.getName());
tv_age.setText("" + user.getAge());
}
}
};
private void sendMsg(User user){
if (mMessageManager==null) {
attemptToBindService();
}
try {
mMessageManager.sendMsg(user);
} catch (RemoteException e) {
e.printStackTrace();
}
}
private User getMsg(){
if (mMessageManager==null) {
attemptToBindService();
}
try {
User user = mMessageManager.getMsg();
return user;
} catch (RemoteException e) {
e.printStackTrace();
}
return null;
}
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;
}
};
private void hideInputMethod(Activity act, View v) { //关闭输入法
InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(),0);
}
@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="com.zhyan8.binder_c.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="姓名:"
android:textSize="30sp"/>
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="40dp"
android:textSize="30sp"
android:background="#ffcc66"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="年龄:"
android:textSize="30sp"/>
<EditText
android:id="@+id/et_age"
android:layout_width="match_parent"
android:layout_height="40dp"
android:textSize="30sp"
android:inputType="number"
android:background="#ffcc66"/>
</LinearLayout>
<Button
android:id="@+id/btn_send"
android:layout_width="match_parent"
android:layout_height="80dp"
android:text="发送"
android:textSize="30sp"
android:layout_marginTop="30dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="50dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="姓名:"
android:textSize="30sp"/>
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="40dp"
android:textSize="30sp"
android:background="#ffcc66"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="年龄:"
android:textSize="30sp"/>
<TextView
android:id="@+id/tv_age"
android:layout_width="match_parent"
android:layout_height="40dp"
android:textSize="30sp"
android:background="#ffcc66"/>
</LinearLayout>
<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>
界面如下:

5 效果展示
(1)发送消息
在2个 EditView 中分别输入::小明、20,点击【发送】按钮,在服务端可以收到发送的消息,如下。

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

声明:本文转自【Android】使用Binder实现进程间传递对象案例
【Android】使用Binder实现进程间传递对象案例的更多相关文章
- 在Android中通过Intent使用Bundle传递对象
IntentBundle传递对象SerializableParcelable Android开发中有时需要在应用中或进程间传递对象,下面详细介绍Intent使用Bundle传递对象的方法.被传递的对象 ...
- IBinder对象在进程间传递的形式(一)
命题 当service经常被远程调用时,我们经常常使用到aidl来定一个接口供service和client来使用,这个事实上就是使用Binder机制的IPC通信.当client bind servic ...
- Android学习笔记_23_服务Service之AIDL和远程服务实现进程通信以及进程间传递自定义类型参数
一.了解AIDL语言: 在Android中, 每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢? 显然, Java中是不支持跨进程内存共享的.因此要传递对象, 需要把对象解析 ...
- C#中使用SendMessage在进程间传递数据的实例
原文:C#中使用SendMessage在进程间传递数据的实例 1 新建解决方案SendMessageExample 在解决方案下面新建三个项目:CopyDataStruct,Receiver和Send ...
- 进程间传递文件描述符——sendmsg和recvmsg函数
先引入一个例子,该程序的目的是子进程向父进程传递文件描述符,并通过该文件描述符读取buf. #include <func.h> int main(){ int fds[2]; pipe(f ...
- WPF 进程间传递参数
WPF 进程间传递参数 在软件开发中有时需要在一个软件中启动另一个软件,这时用Process.Start(“软件路径”)可以启动另一个软件.如果在这个过程中还需要传递一些参数给新启动 ...
- 进程间传递文件描述符fd
众所周知,子进程会继承父进程已经打开的文件描述符fd,但是fork之后的是不会被继承的,这个时候是否无能无力了?答应是NO.Linux提供了一个系统调用sendmsg,借助它,可以实现进程间传递文件描 ...
- Linux 进程间传递文件描述符
文章目录 文件描述符 文件数据结构 共享文件 UNIX域socket实现传递文件描述符 进程间传递打开的文件描述符,并不是传递文件描述符的值.先说一下文件描述符. 文件描述符 对内核来说,所有打开的文 ...
- Android菜鸟的成长笔记(22)——Android进程间传递复杂数据(AIDL)
在上一篇中介绍了Andorid中的进程间的通信方式AIDL,本篇文章将介绍传递复杂数据的AIDL Service 下面通过一个示例说明: 本例子中用到了两个自定义类型:Person与Pet, 其中Pe ...
- android页面间传递对象
android传递对象有两种方式: 一种是Serializable和Parcelable 对于第一种方式: import java.io.Serializable; public class Shop ...
随机推荐
- 【转】嵌入式C语言代码优化方案
来源:嵌入式C语言代码优化方案(深度好文,建议花时间研读并收藏) (qq.com) 1.选择合适的算法和数据结构 选择一种合适的数据结构很重要,如果在一堆随机存放的数中使用了大量的插入和删除指令,那使 ...
- window-子系统-ubuntu
window-子系统-ubuntu 1. 背景 提供类Linux开发环境(命令行.文件系统.进程管理.网路) 2. 安装 A. wsl 安装 下载链接: https://wslstorestorage ...
- 持续集成指南:Gitlab CI/CD 自动部署前端项目
前言 之前陆续写了 Gitlab 的安装使用还有 Gitlab CI/CD 的配置使用,已经把 AspNetCore 的后端项目都做了持续集成了,尝到甜头之后,现在前端的项目也要加入自动化部署,所以经 ...
- 使用Grafana监控Nacos的简单过程
使用Grafana监控Nacos的简单过程 背景 与kafka一样,想同期监控一下nacos. 发现nacos跟minio等一样都有对应的 metrics的暴露接口. 所以这边简单使用一下. stud ...
- [转帖]Shell脚本数组(实现冒泡排序,直接选择排序,反转排序)
目录 数组 数组定义方法 数组包括的数据类型 获取数组长度 读取某下标赋值 数组遍历 数组切片 数组替换 删除数组 追加数组中的元素 从函数返回数组 加法传参运算 乘法传参运算 数组排序算法 冒泡排序 ...
- [转帖]没 K8s 用不了 Chaos Mesh?试试 Chaosd
https://cn.pingcap.com/blog/cannot-use-chaosmesh-without-k8s-then-try-chaosd Chaosd 是什么? 相信大家对 Chaos ...
- [转帖]SIMD+SSE+AVX
http://home.ustc.edu.cn/~shaojiemike/posts/simd/ SIMD SIMD全称Single Instruction Multiple Data,单指令多数 ...
- [百度贴吧]部分CPU的SPEC2006int 结果
这些测试成绩基本上是本人自己测试的结果.下表中有来自spec官网的两个成绩,因为测试年份较早,系统环境和编译器都较老,测试成绩本人实测的还差,所以仅作为参考.部分测试启用了自动并行和附加的优化库,是为 ...
- MySQL查询聚合函数与分组查询
连接数据库 mysql -hlocalhost -uroot -proot 聚合函数 聚合函数:作用于某一列,对数据进行计算. ps: 所有的null值是不参与聚合函数的运算的. 06 常见的聚合函数 ...
- git创建分支出现 fatal: Not a valid object name: 'master'.
今天使用git 创建新分支的时候 出现了一个错误 fatal: Not a valid object name: 'master'. 问题描述:一个非法的master,原因:本地还没有创建master ...