4. Binder对象传递

任务说明

本案例目标是在AIDL接口中传递自定义Parcelable对象,实现跨进程传输复杂数据。我们将创建一个包含用户信息(姓名、年龄、邮箱)的UserInfo对象,通过AIDL接口从客户端发送到服务端,服务端接收后返回处理结果,验证自定义对象能够正确跨进程传输。

实现方案

采用Android标准AIDL+Parcelable机制:定义UserInfo类实现Parcelable接口,创建对应的AIDL文件声明该类型,在服务端AIDL接口方法中接收该对象并返回处理后的字符串。客户端绑定服务后调用接口方法,观察返回结果验证传输成功。

SVG:跨进程对象传递时序

客户端进程 MainActivity IUserManager.Stub.Proxy 服务端进程 UserManagerService IUserManager.Stub Binder Driver transact() Parcel: UserInfo对象 onTransact() 解析 reply: 处理结果字符串 返回结果 请求方向 响应方向

代码实现

1. 定义Parcelable对象 UserInfo.java


package com.example.binderdemo;

import android.os.Parcel;
import android.os.Parcelable;

public class UserInfo implements Parcelable {
    private String name;
    private int age;
    private String email;

    public UserInfo(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }

    protected UserInfo(Parcel in) {
        name = in.readString();
        age = in.readInt();
        email = in.readString();
    }

    public static final Creator<UserInfo> CREATOR = new Creator<UserInfo>() {
        @Override
        public UserInfo createFromParcel(Parcel in) {
            return new UserInfo(in);
        }

        @Override
        public UserInfo[] newArray(int size) {
            return new UserInfo[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(age);
        dest.writeString(email);
    }

    public String getName() { return name; }
    public int getAge() { return age; }
    public String getEmail() { return email; }
}

2. 声明AIDL类型 UserInfo.aidl


package com.example.binderdemo;

parcelable UserInfo;

3. 定义AIDL接口 IUserManager.aidl


package com.example.binderdemo;

import com.example.binderdemo.UserInfo;

interface IUserManager {
    String processUser(in UserInfo user);
}

4. 服务端实现 UserManagerService.java


package com.example.binderdemo;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class UserManagerService extends Service {
    private static final String TAG = "UserManagerService";

    private final IUserManager.Stub binder = new IUserManager.Stub() {
        @Override
        public String processUser(UserInfo user) {
            Log.d(TAG, "收到客户端对象: " + user.getName() + ", " + user.getAge() + ", " + user.getEmail());
            // 模拟业务处理:将年龄加1后返回
            return "处理完成: " + user.getName() + " 明年" + (user.getAge() + 1) + "岁";
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}

5. 客户端调用 MainActivity.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.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private IUserManager userManager;
    private TextView resultText;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            userManager = IUserManager.Stub.asInterface(service);
            sendUser();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            userManager = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        resultText = findViewById(R.id.result_text);

        Intent intent = new Intent(this, UserManagerService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    private void sendUser() {
        try {
            UserInfo user = new UserInfo("张三", 25, "zhangsan@example.com");
            String result = userManager.processUser(user);
            resultText.setText(result);
        } catch (RemoteException e) {
            resultText.setText("调用失败: " + e.getMessage());
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(connection);
    }
}

6. AndroidManifest.xml 注册服务


<service android:name=".UserManagerService"
    android:exported="false">
</service>

落地与验证

文件清单:UserInfo.java、UserInfo.aidl、IUserManager.aidl、UserManagerService.java、MainActivity.java、activity_main.xml(含一个id为result_text的TextView)。

构建步骤:将上述文件放入同一Android工程,确保AIDL文件与Java包名一致,编译生成后安装到设备或模拟器。

验证方法:启动应用,观察界面TextView显示内容。若显示“处理完成: 张三 明年26岁”,说明自定义Parcelable对象已成功从客户端跨进程传递到服务端,且服务端正确读取了对象字段并返回处理结果。同时可在Logcat中过滤UserManagerService标签,查看服务端打印的日志确认收到对象数据。

判定标准:界面显示上述预期文本且Logcat出现对应日志,即验证通过。若出现ClassNotFoundException或TransactionTooLargeException,需检查AIDL声明与Parcelable实现是否匹配。