修改之前那个测试Binder通信的demo测试下。
定义Book类:
java
package com.example.binderdemo;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable {
public String name;
public int price;
public Book() {}
public Book(String name, int price) {
this.name = name;
this.price = price;
}
protected Book(Parcel in) {
readFromParcel(in);
}
public void readFromParcel(Parcel in) {
name = in.readString();
price = in.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(price);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public String toString() {
return "Book{name='" + name + "', price=" + price + "}";
}
}
Book.aidl:

IDirectionTest.aidl文件如下:
java
package com.example.binderdemo;
import com.example.binderdemo.Book;
interface IDirectionTest {
int add(int a, int b);
void testIn(in Book book);
void testOut(out Book book);
void testInout(inout Book book);
}
服务端进程中的DirectionTestService 代码如下:
java
package com.example.binderdemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class DirectionTestService extends Service {
private static final String TAG = "DirectionTest";
private final IDirectionTest.Stub binder = new IDirectionTest.Stub() {
@Override
public int add(int a, int b) throws RemoteException {
Log.d(TAG, "add(" + a + "," + b + ") = " + (a + b));
return a + b;
}
@Override
public void testIn(Book book) throws RemoteException {
Log.d(TAG, "[in] 收到: " + book);
if (book != null) {
book.name = "服务端偷偷改过的名字";
book.price = 9999;
Log.d(TAG, "[in] 服务端修改后: " + book);
}
}
@Override
public void testOut(Book book) throws RemoteException {
Log.d(TAG, "[out] 收到: " + book);
book.name = "服务端填充的名字";
book.price = 42;
Log.d(TAG, "[out] 服务端填充后: " + book);
}
@Override
public void testInout(Book book) throws RemoteException {
Log.d(TAG, "[inout] 收到: " + book);
if (book != null) {
book.name = "服务端改过的名字-inout";
book.price = 8888;
Log.d(TAG, "[inout] 服务端修改后: " + book);
}
}
};
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return binder;
}
}
客户端进程中的DirectionTestActivity 代码如下:
java
package com.example.binderdemo;
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.util.Log;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.ComponentActivity;
public class DirectionTestActivity extends ComponentActivity {
private static final String TAG = "DirectionTest";
private IDirectionTest remote;
private final StringBuilder logBuilder = new StringBuilder();
private TextView logView;
private final ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
remote = IDirectionTest.Stub.asInterface(service);
appendLog("✅ 已连接 Service: " + name);
}
@Override
public void onServiceDisconnected(ComponentName name) {
remote = null;
appendLog("❌ 已断开: " + name);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout root = new LinearLayout(this);
root.setOrientation(LinearLayout.VERTICAL);
int pad = dp(16);
root.setPadding(pad, pad, pad, pad);
Button btnBind = new Button(this);
btnBind.setText("① 绑定 Service(新进程)");
btnBind.setOnClickListener(v -> bindDirectionService());
root.addView(btnBind);
Button btnIn = new Button(this);
btnIn.setText("② 测试 in 参数");
btnIn.setOnClickListener(v -> testIn());
root.addView(btnIn);
Button btnOut = new Button(this);
btnOut.setText("③ 测试 out 参数");
btnOut.setOnClickListener(v -> testOut());
root.addView(btnOut);
Button btnInout = new Button(this);
btnInout.setText("④ 测试 inout 参数");
btnInout.setOnClickListener(v -> testInout());
root.addView(btnInout);
Button btnClear = new Button(this);
btnClear.setText("清空日志");
btnClear.setOnClickListener(v -> {
logBuilder.setLength(0);
if (logView != null) logView.setText("");
});
root.addView(btnClear);
ScrollView scrollView = new ScrollView(this);
logView = new TextView(this);
logView.setTextSize(12f);
logView.setPadding(0, dp(8), 0, 0);
logView.setTextColor(0xFF333333);
scrollView.addView(logView);
root.addView(scrollView, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT,
1f
));
setContentView(root);
}
private void bindDirectionService() {
if (remote != null) {
appendLog("⚠️ 已经绑定过了");
return;
}
Intent intent = new Intent(this, DirectionTestService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
appendLog("🔗 bindService...");
}
private void testIn() {
if (remote == null) { toast("请先绑定 Service"); return; }
try {
Book book = new Book("客户端原始书籍", 10);
appendLog("===== testIn =====");
appendLog("调用前: " + book);
remote.testIn(book);
appendLog("调用后: " + book);
appendLog("🔍 in → 服务端修改丢失 ✅");
} catch (RemoteException e) {
Log.e(TAG, "testIn failed", e);
}
}
private void testOut() {
if (remote == null) { toast("请先绑定 Service"); return; }
try {
Book book = new Book("我在客户端初始化的", 1);
appendLog("===== testOut =====");
appendLog("调用前: " + book);
remote.testOut(book);
appendLog("调用后: " + book);
appendLog("🔍 out → 客户端初始化被丢弃,拿到服务端填充的 ✅");
} catch (RemoteException e) {
Log.e(TAG, "testOut failed", e);
}
}
private void testInout() {
if (remote == null) { toast("请先绑定 Service"); return; }
try {
Book book = new Book("客户端原始书籍", 10);
appendLog("===== testInout =====");
appendLog("调用前: " + book);
remote.testInout(book);
appendLog("调用后: " + book);
appendLog("🔍 inout → 服务端修改同步回来了 ✅");
} catch (RemoteException e) {
Log.e(TAG, "testInout failed", e);
}
}
private void appendLog(String msg) {
Log.d(TAG, msg);
logBuilder.append(msg).append("\n\n");
if (logView != null) {
runOnUiThread(() -> logView.setText(logBuilder.toString()));
}
}
private void toast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
private int dp(int px) {
float density = getResources().getDisplayMetrics().density;
return (int) (px * density + 0.5f);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (connection != null) {
unbindService(connection);
}
}
}
AndroidManifest文件如下:

运行:

先点击绑定服务,再分别点击下面几个按钮:

ok. 可以看出in修饰的字段数据流是从客户端单向流向服务端,只读,服务端修改没用。
而out字段的数据流是从服务端流向客户端,而且服务端也获取不到客户端传的具体值,客户端传的值只是一个空架子给服务端填充的,正如日志:

而inout是双向数据流。