赞
踩
1 在与远程(即另一进程)的service进行通信的时候,需要在远程建立一个aidl接口文件。接口文件定义在src目录下的自建的包内,如
其中ICalcAIDL文件为主接口文件,其内容为
- package com.txt.aidl;
-
- //import com.txt.aidl.IListener;
-
- interface ICalcAIDL{
- int add(int x, int y);
- int max(int x, int y);
- //void register(IListener ilistener);
- }
①之前有个错误是在interface前面加上了public,编译器报错
编辑好之后默认会在gen文件夹下面生成对应的.java文件,即ICalcAIDL.java
服务端service用到的就是这个接口的内部类ICalcAIDL.Stub,它是一个Binder对象,从源码中可以看到
public static abstract class Stub extends android.os.Binder implements com.txt.aidl.ICalcAIDL
另外有两个我们定义的方法需要实现
public int add(int x, int y) throws android.os.RemoteException;
public int max(int x, int y) throws android.os.RemoteException;
service中onBind方法返回的Binder对象定义如下:
- @Override
- public IBinder onBind(Intent intent) {
- // TODO Auto-generated method stub
- Log.i(TAG, "onBind");
- return mBinder;
- }
- private ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub() {
-
- @Override
- public int max(int x, int y) throws RemoteException {
- // TODO Auto-generated method stub
- return x-y;
- }
-
- @Override
- public int add(int x, int y) throws RemoteException {
- // TODO Auto-generated method stub
-
- return x+y;
- }
-
-
- };

然后activity中定义ServiceConnection对象,从而获得ICalcAIDL对象
- <span style="white-space:pre"> </span>private ICalcAIDL mCalcAIDL;
- private ServiceConnection conn = new ServiceConnection() {
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- // TODO Auto-generated method stub
- mCalcAIDL = null;
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- // TODO Auto-generated method stub
- mCalcAIDL = ICalcAIDL.Stub.asInterface(service);
-
- }
- };

拿到mClacAIDL对象后,就和服务端service关联上了,操作该对象的add()和max()方法就能主动通知service做具体的事情了。
activity主动通知service做事情的大致流程就是这样建立起来的了。
3 那么远程service如何主动通知本地activity做什么事情呢,显然我们需要使用回调接口。(同一进程中的activity和service双向通信也是需要在activity中注册一个service提供的回调接口来实现的)。
这里由于是跨进程,这里的回调接口也必须是定义成aidl文件形式②,我的第二个错误就是犯在这里的。
我在ICalcAIDL接口中定义一个注册回调的方法
void register(IListener ilistener);
刚开始我把IListener 这个接口直接定义成java文件,结果在ICalcAIDL接口编译器就报错了,说找不到这个IListener 接口的定义。
后来我把IListener 这个接口也定义成aidl文件,结果就正确了。
所以我得出一个结论,在某个aidl文件中使用到的其他类的对象,必须也是由aidl文件定义的。
于是,我在服务端的工程中的com.txt.aidl包中又定义了这个回调接口IListener.aidl
- package com.txt.aidl;
-
- interface IListener {
- void change(String string);
- }
并在ICalcAIDL中增加了注册函数
- package com.txt.aidl;
-
- import com.txt.aidl.IListener;
-
- interface ICalcAIDL{
- int add(int x, int y);
- int max(int x, int y);
- void register(IListener ilistener);
- }
- private ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub() {
-
- @Override
- public int max(int x, int y) throws RemoteException {
- // TODO Auto-generated method stub
- return x-y;
- }
-
- @Override
- public int add(int x, int y) throws RemoteException {
- // TODO Auto-generated method stub
- if(mListener!=null){
- Log.i(TAG, "调用回调函数");
- mListener.change("远程服务主动通知activity");
- }
- return x+y;
- }
-
- @Override
- public void register(IListener ilistener) throws RemoteException {
- // TODO Auto-generated method stub
- mListener = ilistener;
- }
- };

当我需要通知activity做事情的时候,只要调用这个接口的方法就行了。
4 客户端activity工程中同样需要把IListener.java文件加入到com.txt.aidl包中
客户端activity在serviceConnection对象中注册一个IListener回调接口
- private ServiceConnection conn = new ServiceConnection() {
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- // TODO Auto-generated method stub
- mCalcAIDL = null;
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- // TODO Auto-generated method stub
- mCalcAIDL = ICalcAIDL.Stub.asInterface(service);
- try {
- mCalcAIDL.register(new IListener.Stub() {
-
- @Override
- public void change(String string) throws RemoteException {
- // TODO Auto-generated method stub
- Toast.makeText(RemoteActivity.this, string, Toast.LENGTH_SHORT).show();
- }
- });
- } catch (RemoteException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- };

在这里,我犯了第3个错误,
③在register方法里面我传入了一个IListener对象,而不是IListener.Stub对象,这就直接导致,服务端调用回调接口的change()并不能触发客户端的change()方法。
显然,这里必须使用Stub这个子类来实例化Ilistener对象。
ps:有时候总是止于一知半解,这是第三次学习跨进程通信了,感觉又进步了一点点。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。