分析CmProcess跨进程通信的实现

一、基础知识准备

1.1、多进程

Android多进程概念:一般一个 app 只有一个进程,所有的 components 都运行在同一个进程中,进程名称就是 app 包名。但是每一个进程都有内存的限制,如果一个进程的内存超过了这个限制的时候就会报 OOM 错误。为了解决内存限制的问题,Android 引入了多进程的概念,将占用内存的操作放在一个单独的进程中分担主进程的压力。

多进程的好处:

  • 分担主进程的内存压力。
  • 常驻后台任务。
  • 守护进程,主进程和守护进程相互监视,有一方被杀就重新启动它。
  • 多么块,对有风险的模块放在单独进程,崩溃后不会影响主进程的运行。

多进程的缺点:

  • Applicaton的重新创建,每个进程有自己独立的virtual machine,每次创建新的进程就像创建一个新的Application
  • 静态成员变量和单例模式失效,每个进程有自己独立的虚拟机,不同虚拟机在内存分配上有不同的地址空间,这就导致不同虚拟机在访问同一个对象时会产生多分副本。
  • SharedPreference的可靠性下降,不支持多进程
  • 线程同步机制失效

1.2、Bundle类

bundle 定义 bundle 是一个 final 类,final 类通常功能是完整的,它们不能被继承。Java 中有许多类是 final 的,譬如 String, Interger 以及其他包装类。

public final class Bundle extends BaseBundle implements Cloneable, Parcelable

bundle 传递的数据可以是 boolean、byte、int、long、float、double、string 等基本类型或它们对应的数组,也可以是对象或对象数组。但是如果传递对象或对象数组,该对象必须实现 Serializable 或 Parcelable 接口。由 Bundle 定义我们也可以看到其实现了 Parcelable 接口,所以支持实现了Parcelable 接口的对象。
因此当我们在一个进程中启动了另外一个进程的 Activity、Service、Receiver,我们就可以在 Bundle 中附加我们需要传输给远程进程的信息(前提是能够被序列化)并通过 Intent 发送出去。

二、代码解析

2.1、AIDL接口

1、IEventReceiver:事件接收器

// 事件接受器
interface IEventReceiver {
   // 这里的 event 是 bundle 类型
    void onEventReceive(String key,in Bundle event);
}

2、IPCCallback:看名字也可以看出来是跨进程 callback

interface IPCCallback {
   // result 也是 bundle
    void onSuccess(in Bundle result);
    void onFail(String reason);
}

3、IServiceFetcher:获取服务的。可以再此进行注册。

interface IServiceFetcher {   // service 是 Ibinder 类型
    android.os.IBinder getService(java.lang.String name);   // 注册服务
    void addService(java.lang.String name, android.os.IBinder service);   // 添加回调
    void addEventListener(java.lang.String name, android.os.IBinder service);   // 移除 service
    void removeService(java.lang.String name);   // 移除回调
    void removeEventListener(java.lang.String name);  // 发送消息
    void post(String key,in Bundle result);
}

2.2、启动分析

根据代码可知,咱们有三个进程,分别是:

  • com.ipc.code:vc :TestActivity 运行所在的进程;这是属于用户测的。
  • com.ipc.code:vm : 也就是BinderProvider 存在的进程;IPCBus 也在该进程,主要是用于保存和传递数据
  • com.ipc.code :MainActivity 主进程;

也就是每个进程在初始化的时候,都会走一遍Application 的初始化,因此如果需要对进程做啥操作,可以判断出具体的进程,然后做一些额外的操作。对于 CmProcess ,所有进程的初始化逻辑都是一样的。

public class App extends Application {
    private static final String TAG = "App";

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        // 先启动主进程,之后才启动其他进程
        VCore.init(base);
    }
}

启动过程中,会主动为每个进程注册回调,注意是每个进程。

该 init 方法最终会走入到下面的方法中:

public void startup(Context context) {
        if (!isStartUp) {
            // 在主线程启动,每个进程都有一个自己的主线程
            if (Looper.myLooper() != Looper.getMainLooper()) {
                throw new IllegalStateException("VirtualCore.startup() must called in main thread.");
            }

            ServiceManagerNative.SERVICE_CP_AUTH = context.getPackageName() + "." + ServiceManagerNative.SERVICE_DEF_AUTH;
            this.context = context;
            // 传入了一个 cache 实例,这个实例是只有主线程有的
            IPCBus.initialize(new IServerCache() {
                @Override
                public void join(String serverName, IBinder binder) {
                    ServiceManagerNative.addService(serverName, binder);
                }

                @Override
                public void joinLocal(String serverName, Object object) {
                    ServiceCache.addLocalService(serverName,object);
                }

                @Override
                public void removeService(String serverName) {
                    ServiceManagerNative.removeService(serverName);
                }

                @Override
                public void removeLocalService(String serverName) {
                     ServiceCache.removeLocalService(serverName);
                }

                @Override
                public IBinder query(String serverName) {
                    return ServiceManagerNative.getService(serverName);
                }

                @Override
                public Object queryLocal(String serverName) {
                    return ServiceCache.getLocalService(serverName);
                }

                @Override
                public void post(String key,Bundle bundle) {
                    ServiceManagerNative.post(key,bundle);
                }
            });       // 这里是根据进程名字添加注册的事件接收器
            ServiceManagerNative.addEventListener(AppUtil.getProcessName(context, Process.myPid()), EventReceiver.getInstance());
            isStartUp = true;
        }
    }

这里整个逻辑很简单,就是在主线程初始化了IPCBus,然后给该进程注册了一个事件分发的监听。

三、EventReceiver

public class EventReceiver extends IEventReceiver.Stub {

    private static final String TAG = "EventReceiver";

    private static final EventReceiver EVENT_RECEIVER = new EventReceiver();

    private EventReceiver(){}

    public static final EventReceiver getInstance(){
        return EVENT_RECEIVER;
    }

    @Override
    public void onEventReceive(String key,Bundle event) {
        EventCenter.onEventReceive(key,event);
    }
}

整个类的代码很简单。但是要注意的是,其继承了IEventReceiver.Stub,说明他具有跨进程传输的能力。主要就是通过EventCenter 来分发消息。

由于每个进程都会走一遍初始化逻辑,所以每个进程都注册了事件的接收。

四、ServiceManagerNative

从名字也可以看出来,这个跟我们平时看到的ServiceManager 很像。主要就是用来获取 service 和注册 listener 的。

public static void addEventListener(String name, IBinder service) {
    IServiceFetcher fetcher = getServiceFetcher();
    if (fetcher != null) {
        try {
            fetcher.addEventListener(name, service);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

首先是调用getServiceFetcher 来获取最终保存服务的 fetcher。

注册回调的时候,会先获取是否存在 (binder)ServiceFetcher ,在将其转化为本地 binder;这样 ServiceFetcher 的管理器就可以用了。

private static IServiceFetcher getServiceFetcher() {
    if (sFetcher == null || !sFetcher.asBinder().isBinderAlive()) {
        synchronized (ServiceManagerNative.class) {
            Context context = VirtualCore.get().getContext();
            Bundle response = new ProviderCall.Builder(context, SERVICE_CP_AUTH).methodName("@").call();
            if (response != null) {
                IBinder binder = BundleCompat.getBinder(response, "_VM_|_binder_");
                linkBinderDied(binder);
                sFetcher = IServiceFetcher.Stub.asInterface(binder);
            }
        }
    }
    return sFetcher;
}

首先是看ProviderCall.Builder(context, SERVICE_CP_AUTH).methodName("@").call(),他最终会调用下面的方法:

//ContentProviderCompat
public static Bundle call(Context context, Uri uri, String method, String arg, Bundle extras) {
    // 这里还区分了版本
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
        return context.getContentResolver().call(uri, method, arg, extras);
    }
    ContentProviderClient client = crazyAcquireContentProvider(context, uri);  // 这里会不断重试最终会获得对 BinderProvider 的引用
    Bundle res = null;
    try {
        // 通过约定好的方法名字获得bindle
        res = client.call(method, arg, extras);
    } catch (RemoteException e) {
        e.printStackTrace();
    } finally {
        releaseQuietly(client);
    }
    return res;
} 

五、BinderProvider

下面看下 BinderProvider 的 call 方法。

新建了一个 bundle 对象,然后将 binder 保存在里面。注意这是通过跨进程调用,最终将 bundle 传回主进程,然后拿到了ServiceFetcher 的 binder,并将其转为本地 binder。

可以发现这里对于方法名是 "@" 时,就会返回 bundle ,否则就是返回 null 。

public Bundle call(String method,  String arg,  Bundle extras) {
    if ("@".equals(method)) {
        Bundle bundle = new Bundle();
        BundleCompat.putBinder(bundle, "_VM_|_binder_", mServiceFetcher);
      return bundle;
    }
    return null;
}

简单来说,就是大家都通过 binderProvider 这个进程来保存对于回调的注册,保存是基于进城名字来的,因此可以保证不会被覆盖。

此处的mServiceFetcher 是BinderProvider 内部内的实例,但是其继承了IServiceFetcher.Stub,因此也就有了跨进程的能力。

到这里,理一下前面的逻辑:

ServiceManagerNative.addEventListener(AppUtil.getProcessName(context, Process.myPid()), EventReceiver.getInstance());

某个进程的主线程调用这个方法,所做的具体事情如下:

1.通过 binder 拿到了binderProvider 中的 IServiceFetcher.Stub 的实例;

2.向IServiceFetcher.Stub 注册回调,该回调最终会被保存binderProvider 进程里面。

六、BinderProvider 启动分析

上面介绍了其是怎么将 listener 注册到 binderProvider 进程的,但是并没有讲到接下去我们看下 BinderProvider 的启动过程,

下图是ContentProvider 的启动流程。当我们在主进程想获取 server 的时候,这时候,会看看 provider 存不存在,没有的就会进行启动,同时会走 Application 的初始化逻辑,

具体我们可以看下面这个启动流程图:

  • Application 的 attachBaseContext 方法是优先执行的;
  • ContentProvider 的 onCreate的方法 比 Application的onCreate的方法先执行;
  • Activity、Service 的 onCreate 方法以及 BroadcastReceiver 的 onReceive 方法,是在 MainApplication 的 onCreate 方法之后执行的;
  • 调用流程为: Application 的 attachBaseContext ---> ContentProvider 的 onCreate ----> Application 的 onCreate ---> Activity、Service 等的 onCreate(Activity 和 Service 不分先后);

这里主要是梳理了下 provider 的启动过程,并没有很细讲,但是有必要了解一下。

七、MainActivity

接下去,开始看MainActivity 里面的代码。

调用registerService 注册服务,传入IPayManager.class 和MainActivity;记得MainActivity 也实现了IPayManager 接口。

VCore.getCore().registerService(IPayManager.class, this);

看下,里面的具体代码逻辑

// Vcore
public VCore registerService(Class<?> interfaceClass, Object server){
    if (VirtualCore.get().getContext() == null){
        return this;
    }
    Object o = IPCBus.getLocalService(interfaceClass);
    // 如果是第一次调用就会返回空
    IBinder service = ServiceManagerNative.getService(interfaceClass.getName());
    if (service != null && o != null){
        return this;
    }
    IPCBus.registerLocal(interfaceClass,server);
    // 这里的注册就是把 server 保存到 binder 中
    IPCBus.register(interfaceClass,server);
    return this;
}

这里使用了一个registerLocal和register 方法,但是本质上两个方法是有区别的。registerLocal 意思很明确,就是本地ServiceCache保存一份。但是register,确实做了一些额外的操作。

public static void register(Class<?> interfaceClass, Object server) {
    checkInitialized();
    // 这里主要是获取一个 binder,或者换句话来说,采用 binder 来保存相关数据
    ServerInterface serverInterface = new ServerInterface(interfaceClass);
    // 这里就是把 binder 保存到 binderProvider
    TransformBinder binder = new TransformBinder(serverInterface, server);
    sCache.join(serverInterface.getInterfaceName(), binder);
}

首先这里创建了一个ServerInterface 实例,该实例内部保存了传过了来的接口和接口的方法,并将方法和 code 联系在一起。

public ServerInterface(Class<?> interfaceClass) {
    this.interfaceClass = interfaceClass;
    Method[] methods = interfaceClass.getMethods();
    codeToInterfaceMethod = new SparseArray<>(methods.length);
    methodToIPCMethodMap = new HashMap<>(methods.length);
    for (int i = 0; i < methods.length; i++) {// 这里每一个方法都有一个 code
        int code = Binder.FIRST_CALL_TRANSACTION + i;// 组成一个 ipcMenhod
        IPCMethod ipcMethod = new IPCMethod(code, methods[i], interfaceClass.getName());
        codeToInterfaceMethod.put(code, ipcMethod);// 保存他们的映射关系
        methodToIPCMethodMap.put(methods[i], ipcMethod);
    }
}

同时利用TransformBinder 将接口和 实例保存到 binder 中。再将 binder 和 接口名字 保存到ServiceCache 中。

注册完以后,下面是调用获取本地服务:

// 其实 service 本质还是这个 MainActivity
IPayManager service = VCore.getCore().getLocalService(IPayManager.class);

最后注册了一个回调:

VCore.getCore().subscribe("key", new EventCallback() {
    @Override
    public void onEventCallBack(Bundle event) {

    }
});

最终EventCenter 会保存相关信息;

八、TestActivity

最后启动 TestActivity ,这个是在另一个进程。在 onCreate 里面调用下面的方法:

IPayManager service = VCore.getCore().getService(IPayManager.class);

进程刚刚创建,我们看看是怎么获取服务的:

// Vcore
public <T> T getService(Class<T> ipcClass){
    T localService = IPCBus.getLocalService(ipcClass);
    if (localService != null){
        return localService;
    }
    return VManager.get().getService(ipcClass);
}

这里很明确,本地肯定是没有的,因此,最后会从 VManager 中获取:

// VManager
public <T> T getService(Class<T> ipcClass) {
    T t = IPCBus.get(ipcClass);
    if (t != null){
        return t;
    }
    IPCSingleton<T> tipcSingleton = mIPCSingletonArrayMap.get(ipcClass);
    if (tipcSingleton == null){
        tipcSingleton = new IPCSingleton<>(ipcClass);
        mIPCSingletonArrayMap.put(ipcClass,tipcSingleton);
    }
    return tipcSingleton.get();
}

接下去我们看下IPCSingleton 相关逻辑

// IPCSingleton
public T get() {
    if (instance == null) {
        synchronized (this) {
            if (instance == null) {
                instance = IPCBus.get(ipcClass);
            }
        }
    }
    return instance;
}

这是一个单例,目的也很明确,就是只获取一次,可以看到后面又调到了 IPCBus 里面。

//   IPCBus
public static <T> T get(Class<?> interfaceClass) {
    checkInitialized();
    ServerInterface serverInterface = new ServerInterface(interfaceClass);
    // 这里获取的 binder 应该是 TransformBinder
    IBinder binder = sCache.query(serverInterface.getInterfaceName());
    if (binder == null) {
        return null;
    }
    // 这里使用了动态代理
    return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new IPCInvocationBridge(serverInterface, binder));
}

这里采用了动态代理创造了一个实例,最终返回的实例被保存在一个单例中。

可以看到,这里回去查找存不存在 binder。

// VirtualCore
public IBinder query(String serverName) {
      return ServiceManagerNative.getService(serverName);
}

还是通过ServiceManagerNative 来获取的 service;这里又回到我们之前分析过的逻辑。先从 binderProvider 获取fetcher, 也就是 ServiceFetcher。

IServiceFetcher fetcher = getServiceFetcher();

它也会从ServiceFetcher 中获取到 binder ,而这个 binder 就是之前我们保存的TransformBinder 。拿到这个之后,还是一样,将其转化为该进程的本地 binder .

 // BinderProvider
 private class ServiceFetcher extends IServiceFetcher.Stub {

最后,我们通过动态代理的形式,创建了一个 IPayManager 的实例。

return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new IPCInvocationBridge(serverInterface, binder)); 

这里需要注意的是IPCInvocationBridge 继承自InvocationHandler。

拿到后,开始调用对应的方法:

if (service != null){
    Log.d(TAG, "onCreate: shentest  before   vcore   " + AppUtil.getAppName(this));
    // 首先这个 service 是跨进程调用的,怎么才通知到其他组件?这里大家可以思考下
    service.pay(5000, new BaseCallback() {
        @Override
        public void onSucceed(Bundle result) {
            textview.setText(result.getString("pay"));
            Bundle bundle = new Bundle();
            bundle.putString("name", "DoDo");
            VCore.getCore().post("key",bundle);
        }

        @Override
        public void onFailed(String reason) {

        }
    });
}

调用 service.pay 的时候,就会调用动态代理中的 invoke 方法:

public Object invoke(Object o, Method method, Object[] args) throws Throwable {
    IPCMethod ipcMethod = serverInterface.getIPCMethod(method);
    if (ipcMethod == null) {
        throw new IllegalStateException("Can not found the ipc method : " + method.getDeclaringClass().getName() + "@" +  method.getName());
    }     // 这里很关键
    return ipcMethod.callRemote(binder, args);
}

首先根据方法名获得ipcMethod,里面保存了方法的 code,接口名字,参数,返回值。接着调用了 ipcMethod.callRemote, 该方法又会调用:

// IPCMethod
// 这个方法很重要,需要理解其实现过程
public Object callRemote(IBinder server, Object[] args) throws RemoteException {
    Parcel data = Parcel.obtain(); // 获取一个新的 parcel 对象
    Parcel reply = Parcel.obtain();
    Object result;
    try {
        data.writeInterfaceToken(interfaceName);
        data.writeArray(args);       // 这里 server 就是 transformBinder
        server.transact(code, data, reply, 0);
        reply.readException();
        result = readValue(reply);
        if (resultConverter != null) {
            result = resultConverter.convert(result);
        }
    } finally {
        data.recycle();
        reply.recycle();
    }
    return result;
}

code 变量用于标识客户端期望调用服务端的哪个函数,因此,双方需要约定一组 int 值,不同的值代表不同的服务端函数,该值和客户端的 transact() 函数中第一个参数 code 的值是一致的。

enforceInterface() 是为了某种校验,它与客户端的 writeInterfaceToken() 对应,具体见下一小节。
readString() 用于从包裹中取出一个字符串。如果该 IPC 调用的客户端期望返回一些结果,则可以在返回包裹 reply 中调用 Parcel 提供的相关函数写入相应的结果。 Parcel.writeXXX();

现在要看的是怎么通过 binder 一步一步拿到参数。

使用 Parcel 一般是通过 Parcel.obtain() 从对象池中获取一个新的 Parcel 对象,如果对象池中没有则直接 new 的 Parcel 则直接创建新的一个 Parcel 对象,并且会自动创建一个Parcel-Native 对象。

writeInterfaceToken 用于写入 IBinder 接口标志,所带参数是 String 类型的,如 IServiceManager.descriptor = "android.os.IServiceManager"。

之前说的 code 在这里用上了,code 是一个私有变量,跟 method 绑定在一起的。

中间有个 server.transact(code, data, reply, 0); 该方法实现了跨进程调用,最终会走到 binderProvider 的下面onTransact方法:

// TransformBinder 运行在主进程
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {     // 回调进来后,就到了  MainActivity 的进程
    if (code == INTERFACE_TRANSACTION) {
        reply.writeString(serverInterface.getInterfaceName());
        return true;
    }
    IPCMethod method = serverInterface.getIPCMethod(code);
    if (method != null) {
        try {
            method.handleTransact(server, data, reply);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return true;
    }
    return super.onTransact(code, data, reply, flags);
}

这里主要是根据 code 来获取到是哪个方法被调用了,下面才是真正的处理。

// IPCMethod
public void handleTransact(Object server, Parcel data, Parcel reply) {
    data.enforceInterface(interfaceName); // 确保是目标接口
    Object[] parameters = data.readArray(getClass().getClassLoader());
    if (parameters != null && parameters.length > 0) {
        for (int i = 0; i < parameters.length; i++) {
            if (converters[i] != null) {
                parameters[i] = converters[i].convert(parameters[i]);
            }          // 如果参数里面包含有 binder
            if (parameters[i] instanceof IBinder){
                parameters[i] = IPCCallback.Stub.asInterface(((IBinder)parameters[i]));
            }
        }
    }
    try {
        // 最终通过反射的形式实现了的调用
        // 其实最主要的是通过 binder 拿到参数,然后知道对方调用的是哪个方法。
        // 现在要分析的是,他怎么将数据传过来的
        Object res = method.invoke(server, parameters);
        reply.writeNoException();
        reply.writeValue(res);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
        reply.writeException(e);
    } catch (InvocationTargetException e) {
        e.printStackTrace();
        reply.writeException(e);
    }
}

看看 convert 里面的操作:

public Object convert(Object param) {
    if (param != null) {
        if (asInterfaceMethod == null) {
            synchronized (this) {
                if (asInterfaceMethod == null) {                 // 找到 asInterface 方法
                    asInterfaceMethod = findAsInterfaceMethod(type);
                }
            }
        }
        try {            // 因为 asInterface 方法是静态方法,所以对象可以传入空,最终转变成所需要的参数类型
            return asInterfaceMethod.invoke(null, param);
        } catch (Throwable e) {
            throw new IllegalStateException(e);
        }
    }
    return null;
}

通过 convert 这个一调用,就转变成我们所需要的参数了。

private static Method findAsInterfaceMethod(Class<?> type) {
    for (Class<?> innerClass : type.getDeclaredClasses()) {
        // public static class Stub extends Binder implements IType
        if (Modifier.isStatic(innerClass.getModifiers())
                && Binder.class.isAssignableFrom(innerClass)
                && type.isAssignableFrom(innerClass)) {
            // public static IType asInterface(android.os.IBinder obj)
            for (Method method : innerClass.getDeclaredMethods()) {
                if (Modifier.isStatic(method.getModifiers())) {
                    Class<?>[] types = method.getParameterTypes();
                    if (types.length == 1 && types[0] == IBinder.class) {
                        return method;
                    }
                }
            }
        }
    }
    throw new IllegalStateException("Can not found the " + type.getName() + "$Stub.asInterface method.");
}

findAsInterfaceMethod 通过层层筛选,最终获得需要的那个方法:

public static com.cmprocess.ipc.server.IPCCallback com.cmprocess.ipc.server.IPCCallback$Stub.asInterface(android.os.IBinder)

通过 invoke 方法,终将获得了我们需要的类型。

这里 server 就是 mainActivity。在把对应的参数传进去即可。最终调到了mainActivity 里面的 pay 方法。

public void pay(final int count, final IPCCallback callBack) {

    new Thread(new Runnable() {
        @Override
        public void run() {
            SystemClock.sleep(2000);
            Bundle bundle = new Bundle();
            bundle.putString("pay", count + 100 + "");
            try {
                // callback 也是一个binder
                callBack.onSuccess(bundle);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

此处,callback 也是一个binder,调用成功后,发送了post。 其实最终也是调用了ServiceFetcher 。

// TestActivity
 VCore.getCore().post("key",bundle);

其实也是通过 binder 来进行发送消息的。由于每个进程都注册了消息回调,因此,每个进程都会收到。

// ServiceCache
public static synchronized void sendEvent(String key,Bundle event){
    if (sEventCache.isEmpty()){
        return;
    }
    for (IBinder binder:sEventCache.values()){
        IEventReceiver eventReceiver = IEventReceiver.Stub.asInterface(binder);
        try {
            eventReceiver.onEventReceive(key, event);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

EventReceiver 存在于每个进程,因此,对于 binderprovider 来说都是客户端,其他进程则是服务端。最终 EventCenter 会根据 KEY 值来做分发。

到这里整个流程就基本讲完了。

不过我们发现还有两个 service ,他们的作用是干嘛用的呢?感觉是用来保活的,防止 provider 死了。

以上就是分析CmProcess跨进程通信的实现的详细内容,更多关于CmProcess跨进程通信的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android AIDL实现两个APP间的跨进程通信实例

    本文为大家分享了Android AIDL实现两个APP间的跨进程通信实例,供大家参考,具体内容如下 1 Service端创建 首先需要创建一个Android工程然后创建AIDL文件,创建AIDL文件主要为了生成继承了Binder的Stub类,以便应用Binder进行进程间通信 servier端结构如下 AIDL代码如下 // IBookManager.aidl package com.example.bookserver.aidl; // Declare any non-default type

  • 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跨进程IPC通信AIDL机制原理

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

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

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

  • Android编程实现AIDL(跨进程通信)的方法详解

    本文实例讲述了Android编程实现AIDL(跨进程通信)的方法.分享给大家供大家参考,具体如下: 一. 概述: 跨进程通信(AIDL),主要实现进程(应用)间数据共享功能. 二. 实现流程: 1. 服务器端实现: (1)目录结构,如下图: (2)实现*.aidl文件: A. IAIDLService.aidl实现: package com.focus.aidl; import com.focus.aidl.Person; interface IAIDLService { String getN

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

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

  • Android AIDL实现跨进程通信的示例代码

    AIDL是Android接口定义语言,它可以用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能. 实现步骤 例:用 A程序去访问 B程序的MyService.java服务 在B中建立AIDL文件MyAidlService.AIDL,在AIDL文件里写我们的接口方法 在MyService中写AIDL文件定义的方法的具体服务逻辑 在B的manifest文件中,为Service添加action "com.xyb.servicetest.

  • Android应用程序四大组件之使用AIDL如何实现跨进程调用Service

    一.问题描述 Android应用程序的四大组件中Activity.BroadcastReceiver.ContentProvider.Service都可以进行跨进程.在上一篇我们通过ContentProvider实现了不同应用之间的跨进程调用,但ContentProvider主要是提供数据的共享(如sqlite数据库),那么我们希望跨进程调用服务(Service)呢?Android系统采用了远程过程调用(RPC)方式来实现.与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言

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

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

  • 详解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

随机推荐