当前位置:   article > 正文

Android跨进程通信时犯的错误_找不到符号 throws android.os.remoteexception;

找不到符号 throws android.os.remoteexception;

1 在与远程(即另一进程)的service进行通信的时候,需要在远程建立一个aidl接口文件。接口文件定义在src目录下的自建的包内,如


其中ICalcAIDL文件为主接口文件,其内容为

  1. package com.txt.aidl;
  2. //import com.txt.aidl.IListener;
  3. interface ICalcAIDL{
  4. int add(int x, int y);
  5. int max(int x, int y);
  6. //void register(IListener ilistener);
  7. }
①之前有个错误是在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对象定义如下:

  1. @Override
  2. public IBinder onBind(Intent intent) {
  3. // TODO Auto-generated method stub
  4. Log.i(TAG, "onBind");
  5. return mBinder;
  6. }


  1. private ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub() {
  2. @Override
  3. public int max(int x, int y) throws RemoteException {
  4. // TODO Auto-generated method stub
  5. return x-y;
  6. }
  7. @Override
  8. public int add(int x, int y) throws RemoteException {
  9. // TODO Auto-generated method stub
  10. return x+y;
  11. }
  12. };

2 客户端activity工程中,需要把服务端gen文件夹下面生成的接口类,即全部导入com.txt.aidl包内文件,目前只有ICalcAIDL.java这个文件

然后activity中定义ServiceConnection对象,从而获得ICalcAIDL对象

  1. <span style="white-space:pre"> </span>private ICalcAIDL mCalcAIDL;
  2. private ServiceConnection conn = new ServiceConnection() {
  3. @Override
  4. public void onServiceDisconnected(ComponentName name) {
  5. // TODO Auto-generated method stub
  6. mCalcAIDL = null;
  7. }
  8. @Override
  9. public void onServiceConnected(ComponentName name, IBinder service) {
  10. // TODO Auto-generated method stub
  11. mCalcAIDL = ICalcAIDL.Stub.asInterface(service);
  12. }
  13. };
拿到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

  1. package com.txt.aidl;
  2. interface IListener {
  3. void change(String string);
  4. }
并在ICalcAIDL中增加了注册函数

  1. package com.txt.aidl;
  2. import com.txt.aidl.IListener;
  3. interface ICalcAIDL{
  4. int add(int x, int y);
  5. int max(int x, int y);
  6. void register(IListener ilistener);
  7. }

这样我的service中的binder对象就增加了一个注册方法

  1. private ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub() {
  2. @Override
  3. public int max(int x, int y) throws RemoteException {
  4. // TODO Auto-generated method stub
  5. return x-y;
  6. }
  7. @Override
  8. public int add(int x, int y) throws RemoteException {
  9. // TODO Auto-generated method stub
  10. if(mListener!=null){
  11. Log.i(TAG, "调用回调函数");
  12. mListener.change("远程服务主动通知activity");
  13. }
  14. return x+y;
  15. }
  16. @Override
  17. public void register(IListener ilistener) throws RemoteException {
  18. // TODO Auto-generated method stub
  19. mListener = ilistener;
  20. }
  21. };
当我需要通知activity做事情的时候,只要调用这个接口的方法就行了。
这样服务端的工程文件就变成这样了


4 客户端activity工程中同样需要把IListener.java文件加入到com.txt.aidl包中


客户端activity在serviceConnection对象中注册一个IListener回调接口

  1. private ServiceConnection conn = new ServiceConnection() {
  2. @Override
  3. public void onServiceDisconnected(ComponentName name) {
  4. // TODO Auto-generated method stub
  5. mCalcAIDL = null;
  6. }
  7. @Override
  8. public void onServiceConnected(ComponentName name, IBinder service) {
  9. // TODO Auto-generated method stub
  10. mCalcAIDL = ICalcAIDL.Stub.asInterface(service);
  11. try {
  12. mCalcAIDL.register(new IListener.Stub() {
  13. @Override
  14. public void change(String string) throws RemoteException {
  15. // TODO Auto-generated method stub
  16. Toast.makeText(RemoteActivity.this, string, Toast.LENGTH_SHORT).show();
  17. }
  18. });
  19. } catch (RemoteException e) {
  20. // TODO Auto-generated catch block
  21. e.printStackTrace();
  22. }
  23. }
  24. };
在这里,我犯了第3个错误, ③在register方法里面我传入了一个IListener对象,而不是IListener.Stub对象,这就直接导致,服务端调用回调接口的change()并不能触发客户端的change()方法。

显然,这里必须使用Stub这个子类来实例化Ilistener对象。


ps:有时候总是止于一知半解,这是第三次学习跨进程通信了,感觉又进步了一点点。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/245350
推荐阅读
相关标签
  

闽ICP备14008679号