Android AIDL

来源:互联网 发布:触摸屏是怎样编程 编辑:程序博客网 时间:2024/05/22 15:49

前两天尝试了通过Messenger 实现IPC,但是只能由client向service发送消息,但是Client 不能向Service 发送消息。具体原因是什么至今我还没有查出来,按道理说 Messenger 也是由AIDL实现的,传递到Service 的Messenger也可以向Client发送消息。有兴趣的大侠帮忙解决一下这个问题

Android IPC Messenger app间通讯问题

今天学习了一下AIDL,就在此做一下总结,用我apidemo 的RemoteService 和自己写的程序做一个实例。

Apidemo 的代码可以在SDK Sample中找到,这里说一下几个重点的地方

  1. .aidl文件 aidl 文件可用于声明进程间通讯的接口。aidl文件被Android 编译工具自动生成 java文件,生成文件类中Stub 为实现接口的虚类,其中定义的函数还要功能提供这实现函数功能,用于远程调用。
  2. 在AndroidManifest.xml中注册服务action
        <service android:name=".app.RemoteService" android:process=":remote">            <intent-filter>                <!-- These are the interfaces supported by the service, which                     you can bind to. -->                <action android:name="com.example.android.apis.app.IRemoteService" />                <action android:name="com.example.android.apis.app.ISecondary" />                <!-- This is an action code you can use to select the service                     without explicitly supplying the implementation class. -->                <action android:name="com.example.android.apis.app.REMOTE_SERVICE" />            </intent-filter>        </service>

3 . Service 实现 IRemoteService 类中的 registerCallback 和 unregisterCallback函数,两个函数用于注册回调。至此可以实现双向通信。

    /**     * The IRemoteInterface is defined through IDL     */    private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {        public void registerCallback(IRemoteServiceCallback cb) {            if (cb != null) mCallbacks.register(cb);        }        public void unregisterCallback(IRemoteServiceCallback cb) {            if (cb != null) mCallbacks.unregister(cb);        }    };

mCallback 是一个管理众多Client 回调的集合类,此处要注意我们声明Binder的时候使用的是Stub虚类

4 . client实现IRemoteServiceCallback和注册服务

/**     * main thread handler     */    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {            case MSG_SET_TEXT_VALUE:                textview1.setText("Received from serivce " + msg.arg1);                break;            default:                break;            }            super.handleMessage(msg);        }    };    /**     * service connection     */    ServiceConnection mServiceConnection = new ServiceConnection() {        @Override        public void onServiceDisconnected(ComponentName name) {            try {                mService.unregisterCallback(mCallback);                mService = null;                textview1.setText("not attached");            } catch (RemoteException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            try {                mService = IRemoteService.Stub.asInterface(service);                mService.registerCallback(mCallback);            } catch (RemoteException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    };    /**     * call back method,use for service call client method     */    IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {        @Override        public void valueChanged(int value) throws RemoteException {            mHandler.sendMessage(Message.obtain(null, MSG_SET_TEXT_VALUE, value, 0));        }    };    //注册方法,我从代码中摘出来的    bindService(new Intent(IRemoteService.class.getName()), mServiceConnection,                            Context.BIND_AUTO_CREATE);

此处我讲Handler 代码也贴出来,主要是由于我们声明的 valueChanged 函数不是在main thread 中执行的,因此我们需要更新UI的时候,要通过handler传递给Main thread。

遇到的问题:

@Override            public void onClick(View v) {                // TODO Auto-generated method stub                if (isAttach) {                    button1.setText("Attach");                    try {                        mService.unregisterCallback(mCallback);                    } catch (RemoteException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                    unbindService(mServiceConnection);                    isAttach = false;                } else {                    bindService(new Intent(IRemoteService.class.getName()), mServiceConnection,                            Context.BIND_AUTO_CREATE);                    button1.setText("Detach");                    isAttach = true;                }

此处是button事件响应代码。之前我没有调用 mService.unregisterCallback(mCallback);当我点击解除Service 绑定的时候,TextView 并没有停止执行。
我之前认为当我解除Service 绑定的时候系统回调用onServiceDisconnected(),但仔细查看文档后发现。这个函数只会在连接失效的时候才会调用。失效的情况有Srvice 程序崩溃,或者被关闭等原因。
source code

0 0
原创粉丝点击