Android跨进程抛异常的原理的实现

今天接到了个需求,需要用到跨进程抛异常。

怎样将异常从服务端抛到客户端

也就是说在Service端抛出的异常需要可以在Client端接收。印象中binder是可以传异常的,所以aidl直接走起:

// aidl文件
interface ITestExceptionAidl {
  boolean testThrowException();
}

// service端实现
public class AidlService extends Service {
  @Nullable
  @Override
  public IBinder onBind(Intent intent) {
    return new ITestExceptionAidl.Stub() {

      @Override
      public boolean testThrowException() throws RemoteException {
        if (true) {
          throw new RuntimeException("TestException");
        }
        return true;
      }
    };
  }
}

// client端实现
bindService(intent, new ServiceConnection() {
  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
    ITestExceptionAidl aidl = ITestExceptionAidl.Stub.asInterface(service);

    try {
      aidl.testThrowException();
    } catch (Exception e) {
      Log.e("testtest", "Exception", e);
    }
  }

  @Override
  public void onServiceDisconnected(ComponentName name) {

  }
}, Context.BIND_AUTO_CREATE);

但是这个程序实际上运行起来是这样的:

01-01 05:31:55.475  4868  4880 E JavaBinder: *** Uncaught remote exception!  (Exceptions are not yet supported across processes.)
01-01 05:31:55.475  4868  4880 E JavaBinder: java.lang.RuntimeException: TestException
01-01 05:31:55.475  4868  4880 E JavaBinder:    at me.linjw.demo.ipcdemo.AidlService$1.testThrowException(AidlService.java:22)
01-01 05:31:55.475  4868  4880 E JavaBinder:    at me.linjw.demo.ipcdemo.ITestExceptionAidl$Stub.onTransact(ITestExceptionAidl.java:48)
01-01 05:31:55.475  4868  4880 E JavaBinder:    at android.os.Binder.execTransact(Binder.java:565)

看日志里面的ITestExceptionAidl$Stub.onTransact,也就是说在service端就已经被异常打断了,并没有传给client端,而且第一个大大的”Exceptions are not yet supported across processes.”是说异常不允许跨进程吗?但是我明明记得AIDL生成的代码里面就有向Parcel写入异常啊:

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
  switch (code) {
    case INTERFACE_TRANSACTION: {
      reply.writeString(DESCRIPTOR);
      return true;
    }
    case TRANSACTION_testThrowException: {
      data.enforceInterface(DESCRIPTOR);
      boolean _result = this.testThrowException();
      reply.writeNoException(); // 这里写入的是没有抛出异常
      reply.writeInt(((_result) ? (1) : (0)));
      return true;
    }
  }
  return super.onTransact(code, data, reply, flags);
}

查找Parcel的源码,其实是有writeException方法的:

public final void writeException(Exception e) {
  int code = 0;
  if (e instanceof Parcelable
      && (e.getClass().getClassLoader() == Parcelable.class.getClassLoader())) {
    // We only send Parcelable exceptions that are in the
    // BootClassLoader to ensure that the receiver can unpack them
    code = EX_PARCELABLE;
  } else if (e instanceof SecurityException) {
    code = EX_SECURITY;
  } else if (e instanceof BadParcelableException) {
    code = EX_BAD_PARCELABLE;
  } else if (e instanceof IllegalArgumentException) {
    code = EX_ILLEGAL_ARGUMENT;
  } else if (e instanceof NullPointerException) {
    code = EX_NULL_POINTER;
  } else if (e instanceof IllegalStateException) {
    code = EX_ILLEGAL_STATE;
  } else if (e instanceof NetworkOnMainThreadException) {
    code = EX_NETWORK_MAIN_THREAD;
  } else if (e instanceof UnsupportedOperationException) {
    code = EX_UNSUPPORTED_OPERATION;
  } else if (e instanceof ServiceSpecificException) {
    code = EX_SERVICE_SPECIFIC;
  }
  writeInt(code);
  StrictMode.clearGatheredViolations();
  if (code == 0) {
    if (e instanceof RuntimeException) {
      throw (RuntimeException) e;
    }
    throw new RuntimeException(e);
  }
  writeString(e.getMessage());
  ...
}

可以看到其实Parcel是支持写入异常的,但是只支持Parcelable的异常或者下面这几种异常:

  • SecurityException
  • BadParcelableException
  • IllegalArgumentException
  • NullPointerException
  • IllegalStateException
  • NetworkOnMainThreadException
  • UnsupportedOperationException
  • ServiceSpecificException

如果是普通的RuntimeException,这打断写入,继续抛出。

于是我们将RuntimeException改成它支持的UnsupportedOperationException试试:

// service端改成抛出UnsupportedOperationException
ppublic class AidlService extends Service {
  @Nullable
  @Override
  public IBinder onBind(Intent intent) {
    return new ITestExceptionAidl.Stub() {

      @Override
      public boolean testThrowException() throws RemoteException {
        if (true) {
          throw new UnsupportedOperationException("TestException");
        }
        return true;
      }
    };
  }
}

// client端实现还是一样,不变
bindService(intent, new ServiceConnection() {
  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
    ITestExceptionAidl aidl = ITestExceptionAidl.Stub.asInterface(service);

    try {
      aidl.testThrowException();
    } catch (Exception e) {
      Log.e("testtest", "Exception", e);
    }
  }

  @Override
  public void onServiceDisconnected(ComponentName name) {

  }
}, Context.BIND_AUTO_CREATE);

这样运行的话客户端就能捕获到异常:

01-01 05:49:46.770 19937 19937 E testtest: RemoteException
01-01 05:49:46.770 19937 19937 E testtest: java.lang.UnsupportedOperationException: TestException
01-01 05:49:46.770 19937 19937 E testtest:      at android.os.Parcel.readException(Parcel.java:1728)
01-01 05:49:46.770 19937 19937 E testtest:      at android.os.Parcel.readException(Parcel.java:1669)
01-01 05:49:46.770 19937 19937 E testtest:      at me.linjw.demo.ipcdemo.ITestExceptionAidl$Stub$Proxy.testThrowException(ITestExceptionAidl.java:77)
01-01 05:49:46.770 19937 19937 E testtest:      at me.linjw.demo.ipcdemo.MainActivity$3.onServiceConnected(MainActivity.java:132)
01-01 05:49:46.770 19937 19937 E testtest:      at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1465)
01-01 05:49:46.770 19937 19937 E testtest:      at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1482)
01-01 05:49:46.770 19937 19937 E testtest:      at android.os.Handler.handleCallback(Handler.java:751)
01-01 05:49:46.770 19937 19937 E testtest:      at android.os.Handler.dispatchMessage(Handler.java:95)
01-01 05:49:46.770 19937 19937 E testtest:      at android.os.Looper.loop(Looper.java:154)
01-01 05:49:46.770 19937 19937 E testtest:      at android.app.ActivityThread.main(ActivityThread.java:6097)
01-01 05:49:46.770 19937 19937 E testtest:      at java.lang.reflect.Method.invoke(Native Method)
01-01 05:49:46.770 19937 19937 E testtest:      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1052)
01-01 05:49:46.770 19937 19937 E testtest:      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:942)

跨进程传递异常的原理

好,知道了如何去跨进程传递异常之后,然后我们来看看异常到底是如何传递过去的。

让我们再来看看异常写入的代码:

// 有异常的情况
public final void writeException(Exception e) {
  int code = 0;
  if (e instanceof Parcelable
      && (e.getClass().getClassLoader() == Parcelable.class.getClassLoader())) {
    // We only send Parcelable exceptions that are in the
    // BootClassLoader to ensure that the receiver can unpack them
    code = EX_PARCELABLE;
  } else if (e instanceof SecurityException) {
    code = EX_SECURITY;
  } else if (e instanceof BadParcelableException) {
    code = EX_BAD_PARCELABLE;
  } else if (e instanceof IllegalArgumentException) {
    code = EX_ILLEGAL_ARGUMENT;
  } else if (e instanceof NullPointerException) {
    code = EX_NULL_POINTER;
  } else if (e instanceof IllegalStateException) {
    code = EX_ILLEGAL_STATE;
  } else if (e instanceof NetworkOnMainThreadException) {
    code = EX_NETWORK_MAIN_THREAD;
  } else if (e instanceof UnsupportedOperationException) {
    code = EX_UNSUPPORTED_OPERATION;
  } else if (e instanceof ServiceSpecificException) {
    code = EX_SERVICE_SPECIFIC;
  }
  writeInt(code);
  StrictMode.clearGatheredViolations();
  if (code == 0) {
    if (e instanceof RuntimeException) {
      throw (RuntimeException) e;
    }
    throw new RuntimeException(e);
  }
  writeString(e.getMessage());

  // 之后还有一些写入堆栈的操作,比较多,这里可以不看
}

public final void writeNoException() {
  if (StrictMode.hasGatheredViolations()) {

 // 如果StrictMode收集到了写违规行为会走这里,我们可以不关注它
    writeInt(EX_HAS_REPLY_HEADER);
    ...
  } else {
   // 一般情况下会走这里
    writeInt(0);
  }
}

这里给每种支持的异常都编了个号码,它会往Parcel写入。而0代表的是没有发生异常。然后再看看读取异常的代码:

public boolean testThrowException() throws android.os.RemoteException {
  android.os.Parcel _data = android.os.Parcel.obtain();
  android.os.Parcel _reply = android.os.Parcel.obtain();
  boolean _result;
  try {
    _data.writeInterfaceToken(DESCRIPTOR);
    mRemote.transact(Stub.TRANSACTION_testThrowException, _data, _reply, 0);
    _reply.readException();
    _result = (0 != _reply.readInt());
  } finally {
    _reply.recycle();
    _data.recycle();
  }
  return _result;
}

// android.os.Parcel.readException
public final void readException() {
  int code = readExceptionCode();
  if (code != 0) {
    String msg = readString();

    //在这个方法里面创建异常并且抛出
    readException(code, msg);
  }
}

然后这里有个需要注意的点就是异常必须是写在Parcel的头部的,也就是说如果没有异常,我们先要将0写到头部,然后再将返回值继续往后面写入。如果有异常,我们要先将异常编码写入头部,然后就不需要再写入返回值了。

这样,在客户端读取的时候读取的头部就能知道到底有没有异常,没有异常就继续读取返回值,有异常就将异常读取出来并且抛出。

// service端代码
boolean _result = this.testThrowException();
reply.writeNoException(); // 先写入异常
reply.writeInt(((_result) ? (1) : (0))); // 再写入返回值

// client端代码
mRemote.transact(Stub.TRANSACTION_testThrowException, _data, _reply, 0);
_reply.readException(); // 先读取异常,有异常的话readException方法里面会直接抛出
_result = (0 != _reply.readInt()); // 再读取返回值

也就是Parcel的头部是一个标志位,标志了有异常或者无异常:

但是我们看到AIDL生成的代码都是写入的无异常,那我们抛出的异常是怎么传过去的呢?还记得这个打印吗?

01-01 05:31:55.475  4868  4880 E JavaBinder: *** Uncaught remote exception!  (Exceptions are not yet supported across processes.)
01-01 05:31:55.475  4868  4880 E JavaBinder: java.lang.RuntimeException: TestException
01-01 05:31:55.475  4868  4880 E JavaBinder:    at me.linjw.demo.ipcdemo.AidlService$1.testThrowException(AidlService.java:22)
01-01 05:31:55.475  4868  4880 E JavaBinder:    at me.linjw.demo.ipcdemo.ITestExceptionAidl$Stub.onTransact(ITestExceptionAidl.java:48)
01-01 05:31:55.475  4868  4880 E JavaBinder:    at android.os.Binder.execTransact(Binder.java:565)

我们去android.os.Binder.execTransact这里找找看, onTransact方法实际就是在这里被调用的

private boolean execTransact(int code, long dataObj, long replyObj, int flags) {
 Parcel data = Parcel.obtain(dataObj);
 Parcel reply = Parcel.obtain(replyObj);
 boolean res;

 try {
   res = onTransact(code, data, reply, flags);
 } catch (RemoteException|RuntimeException e) {
   ...
   reply.setDataPosition(0);
   reply.writeException(e);
   res = true;
 } catch (OutOfMemoryError e) {
   RuntimeException re = new RuntimeException("Out of memory", e);
   reply.setDataPosition(0);
   reply.writeException(re);
   res = true;
 }
 checkParcel(this, code, reply, "Unreasonably large binder reply buffer");
 reply.recycle();
 data.recycle();

 return res;
}

看,这里如果catch到了方法,也就是说我们服务端有抛出异常,就会在catch代码块里面先就Parcel的游标重置回0,然后往Parcel头部写入异常。

好,到了这里其实整个流程就差不多了,但是我发现我没有看到那个”Exceptions are not yet supported across processes.”字符串,这个不支持的提示又是哪里来的呢?

让我们再回忆下代码,在遇到不支持的异常类型的时候, writeException也会抛出异常:

public final void writeException(Exception e) {
  int code = 0;
  if (e instanceof Parcelable
      && (e.getClass().getClassLoader() == Parcelable.class.getClassLoader())) {
    // We only send Parcelable exceptions that are in the
    // BootClassLoader to ensure that the receiver can unpack them
    code = EX_PARCELABLE;
  } else if (e instanceof SecurityException) {
    code = EX_SECURITY;
  } else if (e instanceof BadParcelableException) {
    code = EX_BAD_PARCELABLE;
  } else if (e instanceof IllegalArgumentException) {
    code = EX_ILLEGAL_ARGUMENT;
  } else if (e instanceof NullPointerException) {
    code = EX_NULL_POINTER;
  } else if (e instanceof IllegalStateException) {
    code = EX_ILLEGAL_STATE;
  } else if (e instanceof NetworkOnMainThreadException) {
    code = EX_NETWORK_MAIN_THREAD;
  } else if (e instanceof UnsupportedOperationException) {
    code = EX_UNSUPPORTED_OPERATION;
  } else if (e instanceof ServiceSpecificException) {
    code = EX_SERVICE_SPECIFIC;
  }
  writeInt(code);
  StrictMode.clearGatheredViolations();

  // code为0,代表不支持这种异常,继续把异常抛出或者创建RuntimeException抛出
  if (code == 0) {
    if (e instanceof RuntimeException) {
      throw (RuntimeException) e;
    }
    throw new RuntimeException(e);
  }
  ...
}

由于这个writeException,已经是在catch代码块里面运行的了,没有人再去catch它,于是就会打断这个流程,直接跳出。形成了一个Uncaught remote exception。

最后我们找到/frameworks/base/core/jni/android_util_Binder.cpp的onTransact方法,这里通过jni调到Java的execTransact方法,调用完之后进行ExceptionCheck,如果发现有异常的话就report_exception:

virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) {
  JNIEnv* env = javavm_to_jnienv(mVM);

  IPCThreadState* thread_state = IPCThreadState::self();
  const int32_t strict_policy_before = thread_state->getStrictModePolicy();

  jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
    code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);

  if (env->ExceptionCheck()) {
    jthrowable excep = env->ExceptionOccurred();

    // 就是这里啦
    report_exception(env, excep,
      "*** Uncaught remote exception! "
      "(Exceptions are not yet supported across processes.)");
    res = JNI_FALSE;

    env->DeleteLocalRef(excep);
  }
  ...
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android 后台发送邮件示例 (收集应用异常信息+Demo代码)

    上一次说了如何收集我们已经发布的应用程序的错误信息,方便我们调试完善程序.上次说的收集方法主要是把收集的信息通过Http的post请求把相关的异常信息变成请求参数发送到服务器.这个对做过web开发的人来说,服务端处理是很简单.不过对很多没做个web的人来说却是麻烦事.今天介绍个更简单的方法,我们把异常信息收集后,通过后台发送邮件方法,把相关异常信息发送到我们指定的邮箱里面. 这篇文章是实用性文章,不会涉及太多理论分析.主要是让大家看了以后知道怎么在自己的应用里面添加这个功能. 1.第三方库这次发

  • Android 全局异常捕获实例详解

    Android 全局异常捕获 今天就来说说作为程序猿的我们每天都会遇到的东西bug,出bug不可怕可怕的是没有出bug时的堆栈信息,那么对于bug的信息收集就显得尤为重要了,一般用第三方bugly或者友盟等等都能轻易收集,但是由于公司不让使用第三方,而安卓正好有原生的异常收集类UncaughtExceptionHandler,那么今天博客就从这个类开始. UncaughtExceptionHandler见名知意,即他是处理我们未捕获的异常,具体使用分两步 1.实现我们自己的异常处理类 publi

  • Android崩溃异常捕获方法

    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面.而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里.但平时使用的时候给你闹崩溃,那你就欲哭无泪了. 那么今天主要讲一下如何去捕捉系统出现的Unchecked异常.何为Unchecked异常呢,换句话说就是指非受检异常,它不能用try-catch来显示捕捉. 我们先从Exception讲起.Exception分为两类:一种是CheckedException,一种是UncheckedException

  • android 捕获系统异常并上传日志具体实现

    在做项目时,经常会把错误利用异常抛出去,这样在开发时就可以通过手机抛出的异常排查错误.但是当程序开发完毕,版本稳定,需要上线时,为了避免抛出异常影响用户感受,可以用UncaughtExceptionHandler捕获全局异常,对异常做出处理.比如我们可以获取到抛出异常的时间.手机的硬件信息.错误的堆栈信息,然后将获取到的所有的信息发送到服务器中,也可以发送到指定的邮件中,以便及时修改bug. 示例: 自定义异常类实现UncaughtExceptionHandler接口,当某个页面出现异常就会调用

  • 详解Android全局异常的捕获处理

    在Android开发中在所难免的会出现程序crash,俗称崩溃.用户的随意性访问出现测试时未知的Bug导致我们的程序crash,此时我们是无法直接获取的错误log的,也就无法修复Bug.这就会极大的影响用户体验,此时我们需要注册一个功能来捕获全局的异常信息,当程序出现crash信息,我们把错误log记录下来,上传到服务器,以便于我们能及时修复bug.实现这个功能我们需要依赖于UncaughtExceptionHandler这个类,UncaughtExceptionHandler是一个接口,在Th

  • Android自定义抛出异常的方法详解

    前言 在android开发过程中,我们经常遇到异常的问题,崩溃抛出异常的时候,是非常令人烦闷的.但是异常有一个好处,使得app能在编译的时候给我们提供一些bug信息,有时可能比较模糊,有时可能很精准,甚至提示报错行.基于这一点,今天我们就来讲讲android中的异常吧. 今天要讲的内容: throw 和 throws 异常类型 仿写异常及其好处 一. throw 和 throws 异常通常的处理方式有 throw/throws 以及 try-catch 两种.今天我们主要讲解throw/thro

  • 解决Android平台中应用程序OOM异常的方法

    在Android平台上面,应用程序OOM异常永远都是值得关注的问题.通常这一块也是程序这中的重点之一.这下我就如何解决OOM作一点简单的介绍. 首先,OOM就是内存溢出,即Out Of Memory.也就是说内存占有量超过了VM所分配的最大. 怎么解决OOM,通常OOM都发生在需要用到大量内存的情况下(创建或解析Bitmap,分配特大的数组等),在这样的一种情况下,就可能出现OOM,据我现在了解到,多数OOM都是因为Bitmap太大.所以,这里我就专门针对如何解决Bitmap的OOM.其实最核发

  • 详解Android中处理崩溃异常

    大家都知道,现在安装Android系统的手机版本和设备千差万别,在模拟器上运行良好的程序安装到某款手机上说不定就出现崩溃的现象,开发者个人不可能购买所有设备逐个调试,所以在程序发布出去之后,如果出现了崩溃现象,开发者应该及时获取在该设备上导致崩溃的信息,这对于下一个版本的bug修复帮助极大,所以今天就来介绍一下如何在程序崩溃的情况下收集相关的设备参数信息和具体的异常信息,并发送这些信息到服务器供开发者分析和调试程序. 我们先建立一个crash项目,项目结构如图: 在MainActivity.ja

  • Android跨进程抛异常的原理的实现

    今天接到了个需求,需要用到跨进程抛异常. 怎样将异常从服务端抛到客户端 也就是说在Service端抛出的异常需要可以在Client端接收.印象中binder是可以传异常的,所以aidl直接走起: // aidl文件 interface ITestExceptionAidl { boolean testThrowException(); } // service端实现 public class AidlService extends Service { @Nullable @Override pu

  • Android 跨进程SharedPreferences异常详解

    Android 跨进程SharedPreferences异常详解 Context c = null; try { c = context.createPackageContext(PREFERENCE_PACKAGE, Context.CONTEXT_IGNORE_SECURITY); } catch (NameNotFoundException e) { e.printStackTrace(); } if (c != null) { SharedPreferences infoSp = c.g

  • Android跨进程传递大数据的方法实现

    最近要从Service端给Client端传递图片数据,之前的数据都是通过aidl传递: 创建 Parcelable文件 ImageData.java public class ImageData implements Parcelable { private byte[] data; public byte[] getData() { return data; } public ImageData(byte[] dataIn) { this.data = dataIn; } public Ima

  • 详解Android跨进程通信之AIDL

    需求描述 进程A调起第三方进程B进行第三方登录 – 实现双向通信 代码(进程A) 1.目录结构 2.LoginActivity.java public class LoginActivity extends AppCompatActivity { private ILoginInterface iLogin; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceSta

  • 详解Android跨进程IPC通信AIDL机制原理

    简介 AIDL:Android Interface Definition Language,即Android接口定义语言,用于生成Android不同进程间进行进程通信(IPC)的代码,一般情况下一个进程是无法访问另一个进程的内存的.如果某些情况下仍然需要跨进程访问内存数据,这时候Android系统就要将其对象分解成能够识别的原数据,编写这一组操作的代码是一项繁琐的工作,但是AIDL对底层进行了抽象的封装,简化了跨进程操作. AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量

  • Android 跨进程模拟按键(KeyEvent )实例详解

      Android 解决不同进程发送KeyEvent 的问题 最近在做有关于Remote Controller 的功能,该功能把手机做成TV的遥控器来处理.在手机的客户端发送消息到TV的android 服务端,服务端接收到客户端的请求消息,模拟KeyEvent命令,发送Key值. 最简单的发送命令为如下代码: public static void simulateKeystroke(final int KeyCode) { new Thread(new Runnable() { public v

  • Android 跨进程通Messenger(简单易懂)

    不需要AIDL也不需要复杂的ContentProvider,也不需要SharedPreferences或者共享存储文件! 只需要简单易懂的Messenger,它也称为信使,通过它可以在不同进程中传递message对象,在message中放入我们需要传递的数据你就可以实现跨进程通讯和传递数据.废话不多说,直接上代码. 首先是服务端: public class Ser extends Service{ @Override public IBinder onBind(Intent intent) {

  • android使用AIDL跨进程通信(IPC)

    AIDL的作用 AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码.如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数. AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量级.它是使用代理类在客户端和实现端传

  • Android实现跨进程接口回掉的方法

    前言 同一个进程内实现接口回掉很简单,这里不做叙述,本文主要讲的是跨进程的接口回掉实现方式.有一种跨进程通信的方式就是使用AIDL,但是单纯的AIDL通信只可以实现客户端访问服务端主动获取Binder对象,如果服务端有变化无法及时通知客户端.现在可以通过AIDL跨进程接口回掉来解决服务端发生变化通知客户端的问题. 谷歌提供了RemoteCallbackList来实现对IInterface的管理.public class RemoteCallbackList<E extends IInterfac

  • Android基于Aidl的跨进程间双向通信管理中心

    得益于最近有点时间和精力,我想起来了一件事.那就是在上家公司,公司要求做一个APP进程间的通信的功能,并不是APP对APP的直接跨进程通信,而是通过一个服务中心,做接收,然后,再转发,避免应用之间耦合性高,不然的话,新增一个APP,其他APP也要进行升级更新(类似于有服务中心的聊天室). 我就花几个小时写点东西吧,顺便记录一下 大家都知道在Android设备上,有很多方式,比如,广播,socket,共享内存,aidl等,其中广播和aidl都是基于android中iBinder机制 广播: 广播有

随机推荐