【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 ...
随机推荐
- Linux性能分析——TOP命令详解
Linux性能分析--TOP命令详解 1.Top命令介绍 Linux系统中,Top命令主要用于实时运行系统的监控,包括Linux内核管理的进程或者线程的资源占用情况. 这个命令对所有正在运行的进程和系 ...
- Laravel - blade 模板继承的使用
1. 模板文件 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...
- JMS微服务开发示例(五)生成短token,实现用户无状态登录
用户token,也可以利用第三方框架生成,JMS也包含了自己的token服务器. 部署TokenServer 到这里下载 tokenserver.zip,然后部署运行TokenServer. 微服务中 ...
- 战略设计- DDD
随着系统的增长,它会变得越来越复杂,当我们无法通过分析对象来理解系统的时候,就需要掌握一些操纵和理解大模型的技术了.本文将介绍一些原则.遵循这些原则,就可以对非常复杂的领域进行建模.大部分这样的决策都 ...
- [转帖]nginx 剖析 request_time和upstream_response_time的误区、区别
https://cloud.tencent.com/developer/article/1767981 首先,澄清一个误区 upstream_response_time必须在upstream配置时才能 ...
- [转帖]Oracle 19c 新特性|增加 VARCHAR2 数据类型的大小限制
JiekeXuAll China Database Union2022-10-13 795 经朋友介绍,我读完 Tim Hall 于 2022 年 9 月 27 日他的博客上发表的博文.10 月 11 ...
- [转帖]你应该知道的Shell 脚本的经典十三问
https://blog.csdn.net/wangzhicheng987/article/details/131031344 1. 为何叫做shell? 我们知道计算机的运作不能离开硬件,但使用者却 ...
- [转帖]058、集群优化之PD
PD调度基本概念 调度流程 调度中还有这还缺来了merge,例如合并空region. store: 基本信息,容量,剩余空间,读写流量等 region: 范围,副本分布,副本状态,数据量,读写流量等 ...
- [转帖]Codis作者黄东旭:细说分布式Redis架构设计和那些踩过的坑
https://dbaplus.cn/news-141-270-1.html Codis是一个分布式Redis解决方案,与官方的纯P2P模式不同,Codis采用的是Proxy-based的方案.今天我 ...
- [转帖]Jmeter跨线程组传参
https://www.cnblogs.com/a00ium/p/10462576.html 我们知道,同一线程组中可以通过"正则表达式提取器"获取其中一个取样器的响应结果中的 ...