Android IPC、多进程与序列化

本文详细介绍了Android中的进程间通信(IPC)机制,包括Android特有的Binder通信方式,以及如何通过Intent、共享文件、AIDL和Socket等方式实现跨进程数据交互。此外,还深入探讨了Android多进程模式下的运行机制和常见问题。

1 Android IPC 简介

IPC是Inter-Process Communication 的缩写,意为进程间通讯或跨进程通信,指两个进程之间进行数据交换的过程。一个进程可以包含多个线程,最简单的情况下,一个进程可以只有一个线程,即主线程(Android的UI线程)。

IPC机制并不是Android独有的,任何一个操作系统都需要有相应的IPC机制,比如Windows上可以通过剪贴板、管道和邮槽等来进行进程间通信;Linux上可以通过命名管道、共享内容、信号量等来进行进行进程间通信。Android中最具特色的通信方式就是Binder,还支持Socket,通过Socket可以实现任意两个终端之间的通信,同一个设备的两个进程也可以通过Socket实现。

IPC的使用场景:只有在多进程的时候才会进行进程间通信

  • 一个进程需要多进程模式实现,比如有些模块由于特殊原因需要运行在单独的进程中、为了加大一个应用可使用的内存所以需要通过多线程来获取多份内存空间。
  • 当前应用需要向其他应用获取数据。

2 Android的多进程模式

Android 通过给四大组件指定android:process属性,即可以开启多线程。

2.1 开启多线程模式

在Android中使用多进程只有一种方法:给四大组件在AndroidManifest中指定android:process属性,value值就是指定的进程名称,无法为一个线程或类等指定其运行时所在的进程。

Demo案例:AndroidManifest

通过shell命令查看:adb shell ps或者adb shell ps | grep com.gqq.xxx.xxx(包名) 查看运行的进程信息:

注意: android:process值::remote指在当前进程名前加上当前包名,可以理解为相对名称,属于当前应用的私有进程,其他应用组件不可以和它跑在同一个进程中。不以:开头的,是一种完整的命名方式,此进程属于全局进程,其他应用通过ShareUID的方式可以和它跑在同一个进程中。

Android系统会为每个应用分配一个唯一的UID,具有相同UID的应用才能共享数据,如果两个应用通过ShareUID跑在同一个线程中,需要应用有相同的ShareUID并且签名相同,跑在同一个线程,除了共享data目录、组件信息,还可以共享内存数据。相当于一个应用的两部分。

2.2 多进程模式的运行机制

Android 为每一个应用分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,导致在不同的虚拟机上访问同一个类的对象会产生多个副本。比如不同进程对静态变量等的修改,不会影响其他进程,那么运行在不同进程的四大组件通过内存共享数据,就会共享失败。
总体,多进程会带来的几方面的问题:

  1. 静态成员和单例模式完全失效
  2. 线程同步机制完全失效
    不在一块内存,不同进程锁的不是同一个对象。
  3. SharePreference的可靠性下降
    SharePreference的底层实现时通过读/写XML文件来实现的,并发读/写都有可能出现问题,所以不支持两个进程同时执行读写操作,否则会导致一定几率的数据丢失。
  4. Application会多次创建
    创建一个进程会创建一个虚拟机,也就是启动一个应用,自然会创建新的Application。运行在同一个进程中的组件属于同一个虚拟机和同一个Application以及分配同一块内存。

Demo案例

通过跨进程通信,可以实现数据交互,实现跨进程通讯的方法:

  1. Intent传递数据
  2. 共享文件和SharePreference
  3. 基于Binder的Messager和AIDL
  4. Socket

3. IPC 基本概念介绍

主要三个概念,帮助更好的理解进程间通信。

  • Serializable 接口
  • Parcelable 接口
  • Binder

Serializable 和 Parcelable接口可以完成对象的序列化,用于通过Intent和Binder传递数据,需要把对象持久化到存储设备上或通过网络传输给其他客户端,可需要通过Serializable完成对象的持久化。

3.1 Serializable 接口

参考Demo

Serializable是java的一个序列化的空接口,提供标准的序列化和反序列化操作,序列化的类需要实现Serializable接口及声明serialVersionUID,而serialVersionUID不是必需的,但是会影响反序列化的结果。serialVersionUID是静态成员变量,不参与序列化过程。反序列化时serialVersionUID与序列化时的serialVersionUID一致,则可以正常序列化。不指定serialVersionUID,如果反序列化时当前类发生了变化,比如增删了某些成员变量,会重新计算当前类hash值并赋与serialVersionUID,导致与序列化时的serialVersionUID不一样,会造成反序列化失败。指定serialVersionUID会在极大程度上避免反序列化的失败,但是如果类发生了结构性的变化,比如类名和成员变量的类型等,还是会反序列化失败,因为无法还原新结构的对象。

// 序列化过程
User user = new User(1, "gqq", false);
ObjectOutputStream out = ObjectOutputStream(new FileOutputStream(file));
out.writeObject();
out.close();
// 反序列化过程
ObjectInputStream in = ObjectInputStream(new FileInputStream(file));
User user = in.readObject();
in.close();

注意:静态成员变量属于类不属于对象,不参与序列化;用transient关键字标记的成员变量不参与序列化。

继承自Serializable的默认序列化过程是可以改变的,可以重写系统的序列化writeObject()和反序列化方法readObject()

3.2 Parcelable接口

Parcelable 是Android提供的一种序列化接口,接口需要实现序列化、反序列化、内容描述。

public class UserModelParcel implements Parcelable{

    private int userId;
    private String userName;
    private boolean isMale;
    private UserParcel userParcel;

     // 反序列化方法
    protected UserModelParcel(Parcel in) {
        userId = in.readInt();
        userName = in.readString();
        isMale = in.readByte() != 0;
        userParcel = in.readParcelable(UserParcel.class.getClassLoader());
    }

    public UserModelParcel(int userId, String userName, boolean isMale, UserParcel userParcel) {
        this.userId = userId;
        this.userName = userName;
        this.isMale = isMale;
        this.userParcel = userParcel;
    }

    // 序列化
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(userId);
        dest.writeString(userName);
        dest.writeByte((byte) (isMale ? 1 : 0));
        dest.writeParcelable(userParcel, flags);
    }

    // 内容描述
    @Override
    public int describeContents() {
        return 0;
    }

    // 反序列化
    public static final Creator<UserModelParcel> CREATOR = new Creator<UserModelParcel>() {
        @Override
        public UserModelParcel createFromParcel(Parcel in) {
            return new UserModelParcel(in);
        }

        @Override
        public UserModelParcel[] newArray(int size) {
            return new UserModelParcel[size];
        }
    };

总结: Serializable 是java的序列化接口,使用简单但是开销比较大,序列化和反序列化都涉及到大量的I/O操作,效率相对较低。Parcelable是Android提供的序列化方法,更适用于Android平台,效率很高,但是使用起来比较麻烦。Parcelable主要用在内存序列化上,序列化存储设备或将序列化后的对象通过网络传输建议使用Serializable。

再贴一遍
参考 Demo

标题SpringBoot智能在线预约挂号系统研究AI更换标题第1章引言介绍智能在线预约挂号系统的研究背景、意义、国内外研究现状及论文创新点。1.1研究背景意义阐述智能在线预约挂号系统对提升医疗服务效率的重要性。1.2国内外研究现状分析国内外智能在线预约挂号系统的研究应用情况。1.3研究方法及创新点概述本文采用的技术路线、研究方法及主要创新点。第2章相关理论总结智能在线预约挂号系统相关理论,包括系统架构、开发技术等。2.1系统架构设计理论介绍系统架构设计的基本原则和常用方法。2.2SpringBoot开发框架理论阐述SpringBoot框架的特点、优势及其在系统开发中的应用。2.3数据库设计管理理论介绍数据库设计原则、数据模型及数据库管理系统。2.4网络安全数据保护理论讨论网络安全威胁、数据保护技术及其在系统中的应用。第3章SpringBoot智能在线预约挂号系统设计详细介绍系统的设计方案,包括功能模块划分、数据库设计等。3.1系统功能模块设计划分系统功能模块,如用户管理、挂号管理、医生排班等。3.2数据库设计实现设计数据库表结构,确定字段类型、主键及外键关系。3.3用户界面设计设计用户友好的界面,提升用户体验。3.4系统安全设计阐述系统安全策略,包括用户认证、数据加密等。第4章系统实现测试介绍系统的实现过程,包括编码、测试及优化等。4.1系统编码实现采用SpringBoot框架进行系统编码实现。4.2系统测试方法介绍系统测试的方法、步骤及测试用例设计。4.3系统性能测试分析对系统进行性能测试,分析测试结果并提出优化建议。4.4系统优化改进根据测试结果对系统进行优化和改进,提升系统性能。第5章研究结果呈现系统实现后的效果,包括功能实现、性能提升等。5.1系统功能实现效果展示系统各功能模块的实现效果,如挂号成功界面等。5.2系统性能提升效果对比优化前后的系统性能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值