前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android进程间通信(一):基础介绍

Android进程间通信(一):基础介绍

作者头像
103style
发布2022-12-19 13:45:56
2500
发布2022-12-19 13:45:56
举报

转载请以链接形式标明出处: 本文出自:103style的博客

《Android开发艺术探索》 学习记录


目录

  • 进程间通信简介
  • Android中的多进程模式
    • 如何开启多进程
    • 多进程模式的运行机制
  • 进程间通信基础概念介绍
    • Serializable接口
    • Parcelable接口
  • 小结

进程间通信简介

进程间通信IPC机制IPC 全称为 Inter-Process Communication

首先我们先了解下什么是进程,什么是线程?

  • 进程: 一般指一个执行单元。PC的一个程序 或者 移动设备的一个应用.
  • 线程:CPU调用的最小单元,是一种有限的系统资源。

一个进程可以包含多个线程。

IPC 不是 Android 独有的,任何一个操作系统都需要相应的 IPC 机制。比如:

  • Windows上可以通过 剪切板、管道和邮槽来进行进程间通信。
  • Linux 上可以 命令管道、共享内存、信号量等来进行进程间通信。

Android 是一种基于 Linux内核 的移动操作系统,它的进程间通信并不能完全继承 Linux,它有自己的进程间通信方式,比如:BinderSocket.


Android中的多进程模式

这里我们主要介绍两个问题:

  • 如何开启开启多进程模式呢 ?
  • 多进程的运行机制是怎样的呢 ?
如何开启开启多进程模式

那就是在 AndroidMainfest 文件中给 四大组件(ActivityServiceReceiverContentProvider) 指定 android:process

当然 我们也可以通过 JNInative层fork 一个进程。

示例:

代码语言:javascript
复制
<activity
    android:name=".SecondActivity"
    android:process=":second" />
<service
    android:name=".TestService"
    android:process="com.lxk.test.testService" />
<receiver
    android:name=".TestReceiver"
    android:process=":testService" />
<provider
    android:name=".TestContentProvider"
    android:authorities="lxk"
    android:process=":testContentProvider" />

:xxx写法 会在前面添加当前的应用包名, 并且该进程为当前应用的私有进程。 不用:xxx写法的 TestService 则属于全局进程,其他应用可以通过 shareUID 方式和它跑在一个进程中。

运行程序,我们可以通过以下 shell 命令来查看.com.lxk.test 为包名

代码语言:javascript
复制
adb shell ps | grep com.lxk.test

多进程的运行机制

《Android开发艺术探索》的作者是这样形容多进程的——“当应用开启了多进程以后,各种奇怪的现象都出现了”。

原因是 Android为每一个进程都分配了一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这会导致一个类的对象会在每一个上都有一个副本。

所以运行在不同进程中的四大组件,只要它们之间通过内存来共享数据,都会共享失败。

一般来说,使用多进程会出现以下问题:

  • 静态成员和单例失效.
  • 线程同步机制完全失效.
  • SharedPreferences的可靠性降低.
  • Application 会多次创建.

进程间通信基础概念介绍

这里我们是对 Serializable接口Parcelable接口Binder 的介绍。

Serializable接口

Serializable是 Java 提供的一个序列化接口,是一个空接口,为对象提供标准的序列化和反序列化操作。

使用示例:

代码语言:javascript
复制
public class User implements Serializable {
    public static final long serialVersionUID = 4516876541857684L;
    public int userId;
    public String name;
    public int age;
}

我们只需要实现 Serializable 接口,其他的工作几乎都被系统自动完成了。

使用 ObjectOutputStreamObjectInputStream 也可以轻松实现对象的序列化和反序列化。

代码语言:javascript
复制
String url = "cache.txt";

User user = new User(1,"lxk",25);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(url));
oos.writeObject(user);
oos.close();

ObjectInputStream ois = new ObjectInputStream(new FileInputStream(url));
User newUser = (User) ois.readObject();
ois.close();

我们注意到示例中有个 serialVersionUID,它是用来做什么的呢? serialVersionUID 一般是 IDE 根据当前类的结构自动生成的它的 hash值,它并不是必须的。 它的作用主要是用来 区分序列化的内容对应的类的结构是否发生了变化,如果结构发生了变化,就会导致序列化失败,程序crash.

当我们不需要序列化某些字段的时候,我们可以用 transient 字段来修饰.

代码语言:javascript
复制
public class User implements Serializable {
    public static final long serialVersionUID = 4516876541857684L;
    public int userId;
    public String name;
    public int age;
    public transient int temp;
}

Parcelable接口

ParcelableAndroid 提供的序列化方式。 Parcelable 也是一个接口,我们只要实现这个接口,然后根据AndroidStudio的提示重写对应方法。

代码语言:javascript
复制
public class User implements Parcelable {
    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }
        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    public int userId;
    public String name;
    public int age;

    protected User(Parcel in) {
        userId = in.readInt();
        name = in.readString();
        age = in.readInt();
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(userId);
        dest.writeString(name);
        dest.writeInt(age);
    }
    @Override
    public int describeContents() {
        return 0;
    }
}

这里先说下,Parcel 内部包装了可序列化的数据,可以在 Binder 中自由传输。

通过以上示例代码,我们知道 序列化是由 writeToParcelParcel 的一系列 write 方法完成的,反序列化是由 CREATORParcel 的一系列 read 方法完成的.

Parcelable的方法说明:

方法

功能

标记位

createFromParcel(Parcel in)

从序列化后的对象中创建原始对象.

newArray(int size)

创建指定长度的原始数据对象数组.

User(Parcel in)

从序列化后的对象中创建原始对象.

writeToParcel(Parcel dest, int flags)

将当前对象写入序列化结构中. flags包含右侧标记为的值. 1 表示 正在写入的对象是一个返回值,一些实现可能在此时释放资源. 2 表示父对象将负责管理名义上跨其内部数据成员复制的重复状态/数据. 几乎所有情况都是 0.

PARCELABLE_WRITE_RETURN_VALUE = 0x0001 PARCELABLE_ELIDE_DUPLICATES = 0x0002

describeContents()

返回当前对象的内容描述. 1 表示包括文件描述符. 几乎所有情况都是 0.

CONTENTS_FILE_DESCRIPTOR = 0x0001

系统为我们提供了许多实现了 Parcelable 接口的类,它们都是可以直接序列化的。比如: IntentBitmapBundle等,同时 ListMap也可以序列化。


Serializable 和 Parcelable对比 Serializable 是Java提供的序列化接口,使用起来简单但是开销大,需要大量的 I/O操作Parcelable 是 Android提供的序列化接口,适合在Android平台,缺点就是使用起来相对麻烦点,但是效率高。

内存序列化 选 Parcelable. 序列化到存储设备 或者 序列化之后进行网络传输 则选 Serializable.


小结

  • 介绍了通过在 AndroidMainfest 文件中给 四大组件指定 android:process即可指定不同的进程。
  • 介绍了 SerializableParcelable 接口的使用和优缺点,内存序列化Parcelable,否则选 Serializable

下一节 通过 AIDL 介绍 Binder 的工作机制

如果觉得不错的话,请帮忙点个赞呗。

以上


本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-10-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 进程间通信简介
  • Android中的多进程模式
    • 如何开启开启多进程模式
      • 多进程的运行机制
      • 进程间通信基础概念介绍
        • Serializable接口
          • Parcelable接口
          • 小结
          相关产品与服务
          文件存储
          文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档