3. 实现跨进程加法服务

实现跨进程加法服务 学习卡片

任务说明

本案例需要完成一个可独立运行的跨进程加法服务:服务端通过AIDL定义加法接口并实现为Service,客户端绑定该Service后远程调用加法方法并获取结果。整个链路包含AIDL接口定义、服务端实现、客户端调用三个部分,全部代码在本案例内给出。

AIDL接口定义

首先创建AIDL文件,声明加法运算的远程接口。该接口只有一个方法add,接收两个整数参数,返回它们的和。


// IAddService.aidl
package com.example.binderdemo;

interface IAddService {
    int add(int a, int b);
}

服务端实现

服务端是一个继承Service的组件,在onBind中返回AIDL接口的Stub实现。加法逻辑直接在Binder线程池中执行,无需额外处理线程同步。


// AddService.java
package com.example.binderdemo;

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

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

    private final IAddService.Stub mBinder = new IAddService.Stub() {
        @Override
        public int add(int a, int b) {
            int result = a + b;
            Log.d(TAG, "add(" + a + ", " + b + ") = " + result);
            return result;
        }
    };

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

客户端调用

客户端通过bindService绑定服务端,在ServiceConnection回调中获取IAddService代理对象,然后调用add方法。由于Binder调用是同步的,这里在子线程中执行以避免阻塞主线程。


// ClientActivity.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 ClientActivity extends AppCompatActivity {
    private IAddService mAddService;
    private TextView mResultText;

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mAddService = IAddService.Stub.asInterface(service);
            // 在子线程中执行远程调用
            new Thread(() -> {
                try {
                    int result = mAddService.add(3, 5);
                    runOnUiThread(() -> mResultText.setText("3 + 5 = " + result));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }).start();
        }

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

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

        Intent intent = new Intent(this, AddService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

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

AndroidManifest配置

服务端需要在Manifest中注册,并声明exported="true"以允许其他应用(或同应用不同进程)绑定。若仅在同一应用内跨进程使用,可省略权限声明。


<service android:name=".AddService"
         android:exported="true" />

跨进程验证配置

为了验证真正的跨进程调用,需要在Manifest中为客户端Activity所在进程与服务端Service配置不同的android:process属性。例如:


<service android:name=".AddService"
         android:exported="true"
         android:process=":remote" />

这样AddService运行在独立的:remote进程中,客户端Activity运行在主进程,从而构成真实的Binder跨进程通信。

SVG:跨进程加法调用时序

客户端进程(主进程) 服务端进程(:remote) ClientActivity IAddService.Stub.asInterface() AddService IAddService.Stub(Binder实现) bindService 返回Binder代理 mAddService.add(3, 5) Binder驱动(内核) 执行 a + b,返回 8 返回结果 8 UI显示:3 + 5 = 8

验证方法与判定标准

运行步骤:

  1. 将上述代码分别放入对应文件,确保AIDL文件在src/main/aidl/com/example/binderdemo/目录下;
  2. 构建并安装应用到两台设备(或使用模拟器与adb),或同一设备上通过android:process=":remote"实现双进程;
  3. 启动ClientActivity,观察界面显示的运算结果。

判定标准:

  • 客户端界面显示“3 + 5 = 8”,说明远程调用成功返回;
  • 通过adb shell ps可看到两个进程(主进程与:remote进程),证明调用确实跨进程;
  • Logcat中过滤AddService标签,能看到add(3, 5) = 8的日志,表明服务端确实执行了加法逻辑。

满足以上三点即可判定案例通过。若界面无结果或崩溃,检查Manifest中Service的进程配置、AIDL包名是否一致,以及客户端是否在子线程中执行了Binder调用。