Android 开发艺术探索笔记(4)

多进程模式的运行机制

这里有个例子,还是Activity A和B,A为主进程,B为设置了process属性的进程,这里创建一个User类,里面定义一个 public static int UserId = 1。 然后在A中去修改UserId = 2并打印,然后B也打印这个值。静态变量应该是大家都可以去修改然后最后打印出来应该一样才对,但这个时候打印的值 A中为2,B中却为1。
原因是Android为每个进程都提供了一个虚拟机去在内存上分配空间地址,这就导致多个虚拟机访问同一个类会产生多个副本。也就是说在A的com.rikka进程和B的com.rikka:remote进程中各有一个User类。所以才出现这种改变了A中的值却没改变B中的值的现象。

一般来说多进程会造成下列问题:
(1)静态成员和单例模式完全失效。
(2)线程同步机制完全失效。
已经不再同一个内存了,不管是锁对象还是锁全局类都不能保证线程同步,因为不同进程锁的不是同一个对象。
(3)SharePreferences可靠性下降。
SharePreferences不支持两个进程去同时执行写操作。因为SharePreferences的底层是通过读/写XML来实现的。
(4)Application会多次创建。
其实一个进程的创建就会伴随一Application(可以用Application中的onCreate()方法来查看PID)的创建。这样说,同一个进程是属于同一个DVM和同一个Application。 一个应用中的多个进程也相当几个不同的应用采用了ShareUID模式。

IPC基础概念

IPC的基础概念包括Serializable接口,Parcelable接口,Binder。
<关于Serializable接口>
序列化的空接口。
serialVersionUID可以定义也可以不用定义。其工作机制是在序列化的时候将serialVersionUID写入文件中,然后反序列化的时候对比文件中的ID和原ID,如果相同则可以反序列化,否则就会报错,文件在中间出现了数据的变化。 所以我们手动去定义一个UID可以很大程度保证反序列化的时候不会出错。静态成员变量因为属于类不属于对象,还有transient关键字标识的成员这些都不会参与序列化过程。

<关于Parcelable接口>
反序列方法由CREATOR来完成,其内部标明了如果创建序列化对象和数组。
假如在序列化的A类中有另外一个需要操作的别的序列化类B,则B需要反序列化需要传递当前线程的上下文类加载器,否则将无法找到类。
List和Map都可以序列化,前提是他们里面的每个元素都是可序列化的。

比较Parcelable和Serializable:
Serializable是JAVA序列化的接口,开销很大,序列化和反序列化都需要大量的I/O操作。
而Pacelable是Andorid序列化的接口,虽然写起来有点麻烦,但是效率很高,更适用于Android平台。Serializable更适合将对象序列化到存储设备中或者序列化后通过网络传输。

<关于Binder>
Binder是一个实现了IBinder接口。
Messenger的底层是AIDL。用Aidl来做例子。我们在写出MyAIDLManager.aidl后系统为我们生成了MyAIDLManager.java这个类。它继承自IInterface接口,同时自己也是一个接口,它里面声明了MyAIDLManager中我们写的方法,然后给每个方法声明了整型id去标识,就是客户端在申请的时候在transact用哪个id,就是哪个方法。接着声明Stub内部类,它是个Binder类,当客户端和服务端位于一个进程的时候不会去走transact,否则就要走transact这个过程。这个逻辑由Stub的内部类Proxy来实现。

  • DESCRIPTOR:
    binder的唯一标识,一般用当前的Binder类名来表示。
  • asInterface(android.os.IBinder obj)
    用于将服务端的Binder对象转换成客户端所需的AIDL接口类型对象,这种转换过程是区分进程的,如果客户端和服务端位于同一个进程,那么此方法返回的就是服务端的Stub对象本身,否则返回的是系统封装后的Stub.Proxy对象。
  • asBinder
    返回当前的Binder对象
  • onTransact
    运行在Binder线程池中。用来处理客户端的请求。服务端同过code来确定方法,从data中取出参数,再用目标方法去执行。执行完以后向rely中写入返回值、
  • Proxy方法1
    这个方法运行在客户端,它调用时,内部:首先创建该方法所需的输入型Parcel对象_data,输出型Parcel对象_reply和返回值对象List,然后把该方法的参数写入_data中,接着调用transact方法发起RPC(远程过程调用),同时当前线程挂起,服务端的onTransact被调用,知道RPC返回后,当前线程继续执行,并从_reply中取出RPC的返回结果,最后返回_reply中的数据。
    下图为客户端到服务端的机制。
    这里写图片描述
    当binder因为异常而死亡的时候,为了解决客户端受到的影响,可以通过linkToDeath设置死亡代理。首先声明一个DeatheathRecipient对象,这是一个接口,其内部只有binderDied,当Binder死亡的时候,系统回调这个方法,然后我们就可以移处之前的binder代理并重新绑定远程服务,然后在绑定之后给binder设置死亡代理。具体代码为:
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathReceipient(){
    publi void binderDied(){
    if(mBookManager ==null)
        reutrn ;
     mBookManager.asBind().unlinkToDeath(mDeathRecipient,0);
     mBook = null;
     //这里重新绑定远程service
    }
};
.....
mService = IMessageBoxManager.Stub.asInterface(binder);
binder.linkToDeath(mDeathRecipient,0);

另外可以通过isBinderAlive判断binder是否死亡。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值