艺术探索笔记:IPC

2 篇文章 0 订阅
1 篇文章 0 订阅

IPC

线程:CPU 调度的最小单位,是一种有限的系统资源。
进程:一个执行单元,一般指一个程序或应用。一个进程可以有多个线程。
私有进程:进程名以 : 开头,不允许其他应用的组件运行在私有进程
全局进程:进程名以 . 开头,其他应用可以通过 ShareUID 方式,将组件运行在全局进程。

IPC 的方式:

  • Intent 传递数据
  • SharePreference、文件、数据库存储
  • Messager
  • Socket
  • AIDL
序列化与反序列化

序列化的本质是数据形式的转化。
将内存中的数据以流的形式写入到磁盘缓存中。
反序列化即将磁盘缓存中的数据读出来,转化为之前的数据将结构。

Serializable
pulic class User implement Serializable {
	private static final long serialVersionUID = 1L;
}
  • 实现 Serializable 接口,需要指定一个 serialVersionUID。

  • 反序列化时,只有反序列化数据中 serialVersionUID 与数据结构中的 serialVersionUID 一致,才能正确的执行反序列化,否则会抛出 InvalidClassException 异常。

  • 当未指定 serialVersionUID 时,会根据类的结构生成 hash 值,作为 serialVersionUID。

  • 若类的成员变量发生改变,hash 值就会发生改变,此时无法进行反序列化。
    若指定了 serialVersionUID,则可以进行反序列化,尽可能的恢复数据。
    但,若是修改了成员变量的类型或修改了类的名称,仍会反序列化失败。

  • 静态成员变量不会参与序列化

  • 使用 transient 关键字标记的成员变量不会参与序列化

Serializable 反序列化时调用了 ObjectInputStream.readObject 内部使用了反射,产生大量临时对象,效率低
Parcelable
public class User implement Parcelable {
	public int describeContents() {
		return 0;
	}
	public void writeParcel(Parcel out, int flags) {
		// out.writeInt(userId);
	}
	public static final Parcelable.CREATOR<User> CREATOR = new Parcelable.CREATOR<User>({
		Creator<User> {
			public User createFromParcel(Parcel in) {
				return new User(in);
			}
			public User[] newArray(int size) {
				return new User[size];
			}
		}
		private User(Parcel in) {
			// userId = in.readInt();
		}
	});
}
  • 序列化由 writeParcel 完成
  • 反序列化由 CREATOR 完成
  • 内容描述由 describeContents 完成,默认返回 0,仅当对象中有文件描述符时返回 1.
Parcelable 实现原理是在内存中建立一块共享数据块,序列化和反序列化均是操作这一块的数据。效率高

内存中传递使用 Parcelable,持久化存储和网络传输使用 Serializable


Bundle

由于Bundle 实现了 Parcelable 借口,所以 Activity、Service、Receiver 都支持在 Intent 中传递 Bundle 数据进行(进程间)通讯。我们可以在 Bundle 中附加能够被序列化的信息,如基本数据类型(已实现 Serializable)、Parcelable 对象、Serializable 对象等。

文件共享

因为 Android 系统基于 Linux,所以可以无限制的对文件进行并发读/写操作,通过多个进程对同一文件进行交换数据也可以达到进程间通信的目的。
SharePreferences、数据库等存储方案本质上仍是文件的一种。由于 Android 系统对 SharePreferences 的读/写有一定的缓存策略,即内存中会有一份 SharePreferences 的缓存,所以多进程下系统对它的读写变得不在可靠,因此,不建议使用。


Binder

Binder 是 Android 中的一种跨进程通讯方式,是 ServiceManager 连接 Manager 与 ManagerService 的桥梁,是客户端与服务端进行通信的媒介。
Binder 主要应用于 AIDL 和 Messager。

AIDL

IMyAidlInterface.png

DESCRIPTOR

Binder 的唯一标识,一般使用 Binder 的类名表示。

asInterface(IBinder obj)

将服务端 Binder 对象转换为客户端 AIDL 接口类型的对象。
如果客户端和服务端在同一进程,返回值为 Stub本身,否则返回 Stub.proxy 对象。

asBinder

返回当前 Binder 对象。

onTransact(int code, Parcel data, Parcel reply, int flags)
  • code: TRANSACT 类型,用来确定所请求的目标方法
  • data: 目标方法所需的参数。
  • reply: 如果目标方法有返回值,向 reply 写入返回值。
  • flags: –
    返回值为 false 时,表示客户端的请求失败,可以用来做权限校验。
Proxy.basicTypes

通过 Parce.obtain() 方法创建输入型对象 _data、输出型对象 _reply;将函数入参、DESCRIPTOR 写入 _data;通过 Binder 对象调用 transact 方法,将 TRANSACT 类型、_data,_reply 传入服务端进行处理之后,从 _reply 中取出返回结果。
从客户端发起请求开始,直至服务端返回数据,客户端当前线程会一直处于挂起状态,所以耗时操作需要做线程切换处理。

unlinkToDeath

在客户端声明一个 DeathRecipient 对象,在 binderDied 函数内部对 Binder 进行移除绑定(并重新绑定)。

deathRecipient = IBinder.DeathRecipient {
    @Override
    fun binderDied() {
		// Binder 死亡时,会回调该方法
        deathRecipient?.apply {
            serviceInterface?.asBinder()?.unlinkToDeath(this, 0)
            serviceInterface = null
        }
    }
}
linkToDeath

客户端绑定远程服务后,为 Binder 设置死亡代理。

val connection = object : ServiceConnection {
    override fun onServiceConnected(name: ComponentName, service: IBinder) {
        serviceInterface = IMyAidlInterface.Stub.asInterface(service)
        try {
            // 对 Binder 对象设置死亡代理,可以通过 Binder.isBinderAlive 函数判断 Binder 是否存活
            deathRecipient?.apply { service.linkToDeath(this, 0) }
            serviceInterface?.basicTypes(0, 1, true, 3f, 4.0, "5")
            serviceInterface?.sum(1, 2)
        } catch (e: RemoteException) {
            e.printStackTrace()
        }
    }
}
Messenger

Messenger 的底层实现是 AIDL。它实际上是对 AIDL 进行了封装,通过 Message 对象在进程间传输数据,Message 中能使用的载体只有 what、arg1、arg2、Bundle 以及 replyTo。Messenger 一次只会处理一个请求,所以服务端不会处理并发请求,不用考虑线程同步的问题。

Socket

Socket 即“套接字”,它是计算机之间进行通信的一种方式,因此我们也可以通过 Socket 实现进程间的通信。Socket 分为 流式套接字(TCP)、数据报套接字(UDP),可以用来传输任意字节流。
Socket 在使用时需要网络权限,且不能在主线程中使用,与在 Android 设备中进行网络请求是相同的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值