Android:AIDL进程间通信基本框架

前景

在某些业务场景下,我们需要在应用中单独开启一个进程进行一些操作。比如性能监控,如果让原始业务和性能监控本身的业务跑在同一个进程下,那么就会导致性能统计的数据的失真。

而进程间通信,一般采用AIDL机制的客户端与服务端通信。

AIDL基础

AIDL只能传递如下几类数据:

  1. java 基本数据类型
  2. 字符串类型 String 和 CharSequence
  3. 集合类型 List 和 Map
  4. 自定义的 Parcelable
  5. 其他 aidl 接口

当传递自定义 Parcelable 时,有三处地方需要注意:

  1. 必须要 import 这个 Parcelable ,即使这个 Parcelable 跟当前的 aidl 在同一个包下。
  2. 参数还需要用 in out inout三种修饰符修饰。in :表示参数由客户端设置;out :表示参数由服务端设置;inout:表示客户端和服务端皆可设置
  3. 必须单独新建一个 aidl 文件来声明 Parcelable,用关键字 parcelable

当传递其他 aidl 接口时,同样必须要 import 这个 aidl 文件

编写完 aidl 文件后,make一下工程,会在 build 下的 generated 下的 source 下的 aidl 目录生成对应的接口类文件。aidl 接口其实就是 API 接口,通过实现对应接口类的 Stub 子类来实现具体的 API 逻辑;通过对应接口类的 Stub 子类的 asInterface 方法得到具体的实现类,调用具体的 API 方法。

AIDL通信结构

一个基本的客户端服务端的通信结构一般包括如下功能

客户端的功能

  1. 主动连接服务端
  2. 主动断开服务端
  3. 从服务端拉取数据
  4. 向服务端推送数据

服务端的功能

  1. 主动连接客户端
  2. 主动断开客户端

客户端的相关功能实现比较简单,麻烦的是服务端的功能。因为 AIDL 接口定义的都是服务端的接口,是由客户端来调用的。而想要实现服务端反向调用客户端则需要通过其他手段实现。

想要实现服务端主动连接客户端,最好的办法就是服务端发送广播,客户端收到广播后再主动连接服务端,通过这种方式变相地实现服务端主动连接客户端的功能

想要实现服务端主动断开客户端,除了上面发送广播是一种实现方式外,还可以通过 android 的系统API RemoteCallbackList,用包名作为key值来注册远程回调接口的方式,让服务端持有客户端的回调接口,服务端调用回调接口,客户端在回调接口中实现主动断开服务端,通过这种方式变量地实现服务端主动断开客户端的功能。而采用后者会显得更加优雅

既然所有的操作归根结底都是由客户端来完成的,那么客户端必须得有如下的功能模块:

  1. 通过 bindService 的方式连接服务端,注意 ServiceConnection 的 onServiceDisconnected 只会在连接意外断开时会被调用,手动调用 unbindService 方法不会被触发
  2. 注册广播接收器,接受来自服务端的连接请求,然后再主动连接服务端
  3. 通过 unbindService 的方式断开服务端
  4. 实现远程回调接口,在连接成功后注册回调接口,在接口中实现主动断开服务端
  5. 开启工作子线程,实现一些具体的业务操作,如连接状态的触发回调等

服务端必须得有的功能模块:

  1. 发送广播给客户端通知申请连接自己
  2. 实现客户端回调接口注册逻辑
  3. 调用客户端的回调接口来断开连接
  4. 实现客户端回调接口的反注册逻辑
  5. 开启工作子线程,实现一些具体的业务操作

那么,整体的通信流程就是如下的步骤:

  1. 客户端主动或者接受到服务端的连接请求广播后,通过 bindService 的方式连接服务端
  2. 在连接成功后的 ServiceConnection 回调中注册回调接口,因为是进程间通信,这个回调接口同样必须是 aidl 接口,只不过是在客户端这边实现在服务端调用。
  3. 服务端处理注册回调接口操作,根据具体的业务实现注册操作,比如只允许一个客户端连接
  4. 注册回调接口成功后,开启服务端的工作线程
  5. 进行数据的拉取和推送,完成进程间的数据通信
  6. 客户端主动或者回调接口调用后,首先停止服务端的工作线程,然后通过 unbindService 的方式断开连接
  7. 在服务端的 onUnbind 方法中,对回调接口进行反注册操作

关键代码的讲解

首先是通信的 aidl 接口定义

// IBinder 的实际连接
interface IGT {

    // 客户端连接成功后,需要注册回调,以便于服务端反向调用客户端
    int register(String key, ICallback callback);

    // 开始业务
    void startBusiness();

    // 结束业务
    void stopBusiness();

    // 从服务端拉取数据
    TransportObject pull();

    // 客户端向服务器推送数据
    void push(in TransportObject object);
}

然后是客户端的连接操作与断开连接操作,包括广播接收者的注册以及回调接口的实现


public void init(Context context) {
    mContext = context.getApplicationContext();
    mContext.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Constants.ACTION_CONNECT.equals(intent.getAction())) {
                connect();
            }
        }
    }, new IntentFilter(Constants.ACTION_CONNECT));
}

private ServiceConnection mConnect = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        IGT gt = IGT.Stub.asInterface(service);
        try {
            int result = gt.register(mContext.getPackageName(), mRemoteCallback);
            if (result == Constants.REGISTER_SUCCESS) {
                // 注册成功,开启业务
                mGT = gt;
                mGT.startBusiness();
                mHandler.sendEmptyMessage(Constants.CLIENT_WHAT_CONNECT_SUCCESS);
            } else {
                // 注册失败
                if (isConnected()) {
                    mGT.stopBusiness();
                }
                mGT = null;
                mHandler.sendEmptyMessage(Constants.CLIENT_WHAT_CONNECT_FAILED);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        // 只有连接意外被终止才会回调,正常关闭连接不会回调
        mGT = null;
        mHandler.sendEmptyMessage(Constants.CLIENT_WHAT_DISCONNECT);
    }
};

private ICallback.Stub mRemoteCallback = new ICallback.Stub() {
    @Override
    public void disconnected() throws RemoteException {
        disconnect();
    }
};

public void connect() {
    if (isConnected()) {
        return;
    }
    Intent intent = new Intent(mContext, GTService.class);
    mContext.bindService(intent, mConnect, Context.BIND_AUTO_CREATE);
}

public void disconnect() {
    if (!isConnected()) {
        return;
    }
    // 断开前,先结束业务
    try {
        mGT.stopBusiness();
    } catch (RemoteException e) {
        e.printStackTrace();
    }
    mContext.unbindService(mConnect);
    mGT = null;
    mHandler.sendEmptyMessage(Constants.CLIENT_WHAT_DISCONNECT);
}

然后是客户端的拉取数据和推送数据操作

public TransportObject pull() {
    if (!isConnected()) {
        return null;
    }
    try {
        return mGT.pull();
    } catch (RemoteException e) {
        e.printStackTrace();
    }
    return null;
}

public void push(TransportObject object) {
    if (!isConnected()) {
        return;
    }
    if (object == null) {
        return;
    }
    try {
        mGT.push(object);
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

public boolean isConnected() {
    return mGT != null;
}

接着是服务端的 iBinder 接口的实现,完成回调接口的注册、业务子线程的开启和关闭、数据的推送和数据的拉取操作

private IGT.Stub mBinder = new IGT.Stub() {
    @Override
    public int register(String key, ICallback callback) throws RemoteException {
        if (TextUtils.isEmpty(key)) {
            callback(key, callback, Constants.REGISTER_ERROR_NULL_KEY);
            return Constants.REGISTER_ERROR_NULL_KEY;
        }

        if (callback == null) {
            callback(key, callback, Constants.REGISTER_ERROR_NULL_CALLBACK);
            return Constants.REGISTER_ERROR_NULL_CALLBACK;
        }

        try {
            int size = remoteCallbacks.beginBroadcast();
            if (size >= Constants.MAX_CLIENT_CONNECT) {
                callback(key, callback, Constants.REGISTER_ERROR_MAX_LIMIT);
                return Constants.REGISTER_ERROR_MAX_LIMIT;
            }
            for (int i = 0; i < size; i++) {
                if (key.equals(remoteCallbacks.getBroadcastCookie(i))) {
                    // 已经注册过
                    callback(key, callback, Constants.REGISTER_ERROR_REPEAT);
                    return Constants.REGISTER_ERROR_REPEAT;
                }
            }
            // 开始注册
            if (remoteCallbacks.register(callback, key)) {
                callback(key, callback, Constants.REGISTER_SUCCESS);
                return Constants.REGISTER_SUCCESS;
            } else {
                callback(key, callback, Constants.REGISTER_ERROR_UNKNOW);
                return Constants.REGISTER_ERROR_UNKNOW;
            }
        } finally {
            remoteCallbacks.finishBroadcast();
        }
    }

    @Override
    public void startBusiness() throws RemoteException {
        if (mHandlerThread == null) {
            mHandlerThread = new HandlerThread(GTService.class.getSimpleName());
            mHandlerThread.start();
            mHandler = new Handler(mHandlerThread.getLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    switch (msg.what) {
                        case Constants.SERVER_WHAT_CREATE:
                            // 模拟1s耗时
                            try {
                                TimeUnit.SECONDS.sleep(1);
                                TransportObject object = new TransportObject("" + System.currentTimeMillis(), "create by GTService");
                                datas.offer(object, Constants.TIMEOUT, TimeUnit.SECONDS);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            break;
                        case Constants.SERVER_WHAT_CONSUME:
                            // 模拟1s耗时
                            try {
                                TimeUnit.SECONDS.sleep(1);
                                datas.poll(Constants.TIMEOUT, TimeUnit.SECONDS);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            break;
                    }
                }
            };
        }
    }

    @Override
    public void stopBusiness() throws RemoteException {
        if (mHandlerThread == null) {
            return;
        }
        mHandlerThread.quit();
        mHandler.removeCallbacksAndMessages(null);
        mHandlerThread = null;
        mHandler = null;
    }

    @Override
    public TransportObject pull() throws RemoteException {
        if (datas.size() == 0) {
            mHandler.sendEmptyMessage(Constants.SERVER_WHAT_CREATE);
        }
        try {
            TransportObject object = datas.poll(Constants.TIMEOUT, TimeUnit.SECONDS);
            callback(null, null, Constants.REGISTER_DATA_CHANGE);
            return object;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        callback(null, null, Constants.REGISTER_DATA_CHANGE);
        return null;
    }

    @Override
    public void push(TransportObject object) throws RemoteException {
        if (datas.size() == Constants.MAX_SERVER_DATA_CONTAIN) {
            mHandler.sendEmptyMessage(Constants.SERVER_WHAT_CONSUME);
        }
        try {
            datas.offer(object, Constants.TIMEOUT, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        callback(null, null, Constants.REGISTER_DATA_CHANGE);
    }
};

然后是服务端的主动连接和主动断开连接操作

public void connect() {
    Intent intent = new Intent(Constants.ACTION_CONNECT);
    sendBroadcast(intent);
}

public void disconnect() {
    try {
        int size = remoteCallbacks.beginBroadcast();
        while (size > 0) {
            ICallback callback = remoteCallbacks.getBroadcastItem(size - 1);
            // 这里只调用业务的disconnected,具体的回调在onUnBind方法中处理
            callback.disconnected();
            size--;
        }
    } catch (RemoteException e) {
        e.printStackTrace();
    } finally {
        remoteCallbacks.finishBroadcast();
    }
}

public void disconnect(String key) {
    if (TextUtils.isEmpty(key)) {
        return;
    }
    try {
        int size = remoteCallbacks.beginBroadcast();
        for (int i = 0; i < size; i++) {
            if (key.equals(remoteCallbacks.getBroadcastCookie(i))) {
                ICallback callback = remoteCallbacks.getBroadcastItem(i);
                // 这里只调用业务的disconnected,具体的回调在onUnBind方法中处理
                callback.disconnected();
                break;
            }
        }
    } catch (RemoteException e) {
        e.printStackTrace();
    } finally {
        remoteCallbacks.finishBroadcast();
    }
}

public boolean isConnected() {
    int size = remoteCallbacks.getRegisteredCallbackCount();
    return size > 0;
}

最后是服务端的 onUnbind 方法的实现,对回调接口进行反注册

public boolean onUnbind(Intent intent) {
    if (intent != null && intent.getComponent() != null
            && !TextUtils.isEmpty(intent.getComponent().getPackageName())) {
        String packageName = intent.getComponent().getPackageName();
        try {
            int size = remoteCallbacks.beginBroadcast();
            for (int i = 0; i < size; i++) {
                if (packageName.equals(remoteCallbacks.getBroadcastCookie(i))) {
                    ICallback callback = remoteCallbacks.getBroadcastItem(i);
                    remoteCallbacks.unregister(callback);
                    // 状态回调通知
                    callback(packageName, callback, Constants.REGISTER_DISCONNECT);
                    break;
                }
            }
        } finally {
            remoteCallbacks.finishBroadcast();
        }
    }
    // 服务插件,这种设计可以在一个Service上开启多个插件,尽量重载Service的每个生命周期
    for (IServicePlugin plugin : plugins) {
        plugin.onUnbind(intent);
    }
    return super.onUnbind(intent);
}

使用

服务端模仿 FloatViewPlugin 自定义插件,实现 IServicePlugin 接口,定制个性化的悬浮窗插件

public class FloatViewPlugin implements IServicePlugin {

    private IServiceCallback callback = new IServiceCallback() {
        @Override
        public void onConnected(String key, ICallback callback) {
            refreshStatus();
        }

        @Override
        public void onConnectFailed(String key, ICallback callback, int errorType) {
            refreshStatus();
        }

        @Override
        public void onDisConnected(String key, ICallback callback) {
            refreshStatus();
        }

        @Override
        public void onDataChanged() {
            refreshDataStatus();
        }
    };

    @Override
    public void onBind(Intent intent) {
        if (GTService.getInstance() == null) {
            return;
        }
        GTService.getInstance().registerCallback(callback);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        if (GTService.getInstance() == null) {
            return false;
        }
        GTService.getInstance().unregisterCallback(callback);
        return false;
    }

    private View initView(Context context) {
        View contentView = View.inflate(context, R.layout.layout_float_view, null);
        connectBtn = contentView.findViewById(R.id.btn_connect);
        disconnectBtn = contentView.findViewById(R.id.btn_disconnect);

        clientListView = contentView.findViewById(R.id.lv_client);
        clientAdapter = new StringAdapter();
        clientListView.setAdapter(clientAdapter);

        contentListView = contentView.findViewById(R.id.lv_content);
        contentAdapter = new StringAdapter();
        contentListView.setAdapter(contentAdapter);

        connectBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (GTService.getInstance() == null) {
                    return;
                }
                GTService.getInstance().connect();
            }
        });
        disconnectBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (GTService.getInstance() == null) {
                    return;
                }
                GTService.getInstance().disconnect();
            }
        });
        clientListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView parent, View view, int position, long id) {
                if (GTService.getInstance() == null) {
                    return;
                }
                GTService.getInstance().disconnect(clientAdapter.getItem(position));
            }
        });
        return contentView;
    }

    private void refreshStatus() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (GTService.getInstance() == null) {
                    return;
                }
                if (GTService.getInstance().isConnected()) {
                    connectBtn.setEnabled(false);
                    disconnectBtn.setEnabled(true);
                } else {
                    connectBtn.setEnabled(true);
                    disconnectBtn.setEnabled(false);
                }
                if (clientAdapter != null) {
                    clientAdapter.setDatas(GTService.getInstance().getAllClientKeys());
                }
            }
        });

    }

    private void refreshDataStatus() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (GTService.getInstance() == null) {
                    return;
                }
                if (contentAdapter != null) {
                    List allDatas = GTService.getInstance().getAllDatas();
                    List stringDatas = new ArrayList<>();
                    if (allDatas != null) {
                        for (TransportObject object : allDatas) {
                            stringDatas.add(object.getKey() + "---" + object.getValue());
                        }
                    }
                    contentAdapter.setDatas(stringDatas);
                }
            }
        });
    }

}

客户端在 Appliaction 的 onCreate方法中初始化

private void initGTModule() {
    GTClient.getInstance().init(this);
}

在 MainActivity 上实现连接、断开、数据通信

public class MainActivity extends AppCompatActivity {

    private IClientCallback callback = new IClientCallback() {
        @Override
        public void onConnected() {
            refreshBtnStatus();
        }

        @Override
        public void onConnectFailed() {
            refreshBtnStatus();
        }

        @Override
        public void onDisConnected() {
            refreshBtnStatus();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = findViewById(R.id.textView);
        connectBtn = findViewById(R.id.btn_connect);
        disconnectBtn = findViewById(R.id.btn_disconnect);
        pullBtn = findViewById(R.id.btn_pull);
        pushBtn = findViewById(R.id.btn_push);

        connectBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                GTClient.getInstance().connect();
            }
        });
        disconnectBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                GTClient.getInstance().disconnect();
            }
        });
        pullBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TransportObject object = GTClient.getInstance().pull();
                if (object != null) {
                    Toast.makeText(MainActivity.this, "获取到数据:key=" + object.getKey() + ",value=" + object.getValue(), Toast.LENGTH_SHORT).show();
                }
            }
        });
        pushBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TransportObject object = new TransportObject("" + System.currentTimeMillis(), "create by client");
                GTClient.getInstance().push(object);
                Toast.makeText(MainActivity.this, "数据发送成功:key=" + object.getKey() + ",value=" + object.getValue(), Toast.LENGTH_SHORT).show();
            }
        });

        GTClient.getInstance().registerConnectCallback(callback);
    }

    @Override
    protected void onDestroy() {
        GTClient.getInstance().unregisterConnectCallback(callback);
        super.onDestroy();
    }

    private void refreshBtnStatus() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (GTClient.getInstance().isConnected()) {
                    connectBtn.setEnabled(false);
                    disconnectBtn.setEnabled(true);
                    pullBtn.setEnabled(true);
                    pushBtn.setEnabled(true);
                } else {
                    connectBtn.setEnabled(true);
                    disconnectBtn.setEnabled(false);
                    pullBtn.setEnabled(false);
                    pushBtn.setEnabled(false);
                }
            }
        });
    }

}

你可能感兴趣的:(Android:AIDL进程间通信基本框架)