0%

IPC 机制(四):Android 中的 IPC 方式

1. 使用 Bundle

  • 四大组件的三大组件:Activity、Service、Receiver 都支持在 Intent 中传递 Bundle 数据,因为 Bundle 实现了 Parcelable 接口,所以它可以方便地在不同的进程间传输。典型场景是:在一个进程中启动另一个进程的 Activity、Service、Receiver,把 Bundle 附加到 Intent 中发送出去
  • 传输的数据必须能够被序列化,比如基本数据类型、实现了 Parcelable 接口的对象、实现了 Serializable 接口的对象以及一些 Android 支持的特殊对象。具体内容可以看 Bundle 这个类,查看 Bundle 所有支持的类型

2. 使用文件共享

  • 两个进程通过读写同一个文件来交换数据,比如 A 进程把数据写入文件,B 进程通过读取这个文件来获取数据

    • Windows 上,一个文件如果加了排斥锁将会导致其他线程无法对其进行访问,包括读和写
    • Android 基于 Linux,使得其并发读写文件可以没有限制地进行,甚至两个线程同时对同一个文件进行写操作都是允许的,尽管这可能出问题
  • 通过文件交换数据除了可以交换一些文本信息外,还可以序列化一个对象到文件系统中的同时从另一个进程中恢复这个对象

    • 通过文件共享这种方式共享数据对文件格式没有具体要求,可以是文本文件也可以是 XML 文件,只要读写双方约定好数据格式即可
    • 通过文件共享的方式也是有局限性的,比如并发读写的问题,有可能读出的内容不是最新的,如果是并发写的话情况更严重
  • 文件共享方式适合在对数据同步要求不高的进程之间进行通信,并且要求妥善处理并发读写的问题

  • SharedPreferences 是个特例

    • SharedPreferences 是 Android 中提供的轻量级存储方案,通过键值对的方式来存储数据,底层实现上采用 XML 文件存储键值对
    • 从本质上来说,SharedPreferences 也属于文件的一种,系统对它的读写有一定的缓存策略:在内存中会有一份 SharedPreferences 文件的缓存
    • 因此在多进程模式下,系统对它的读写就变得不可靠,当面对高并发的读写访问,SharedPreferences 有很大几率会丢失数据
    • 不建议在进程间通信中使用 SharedPreferences
  • Demo:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    // 在 MainActivity 中的修改
    private void persistToFile() {
    new Thread(new Runnable() {
    @Override
    public void run() {
    User user = new User(1, "hello world", false);
    File dir = new File(MyConstants.CHAPTER_2_PATH);
    if (!dir.exists()) {
    dir.mkdirs();
    }
    File cachedFile = new File(MyConstants.CACHE_FILE_PATH);
    ObjectOutputStream objectOutputStream = null;
    try {
    objectOutputStream = new ObjectOutputStream(new FileOutputStream(cachedFile));
    objectOutputStream.writeObject(user);
    Log.d(TAG, "persist user: " + user);
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    MyUtils.close(objectOutputStream);
    }
    }
    }).start();
    }

    // 在 SecondActivity 中的修改
    private void recoverFromFile() {
    new Thread(
    @Override
    public void run() {
    User user = null;
    File cachedFile = new File(MyConstants.CACHE_FILE_PATH);
    if (cachedFile.exists()) {
    ObjectInputStream objectInputStream = null;
    try {
    objectInputStream = new ObjectInputStream(new FileInputStream(cachedFile));
    user = (User) objectInputStream.readObject();
    // 反序列化得到的对象只是在内容上和序列化之前的对象是一样的,但它们本质上还是两个对象
    Log.d(TAG, "recover user: " + user);
    } catch (IOException e | ClassNotFoundException e) {
    e.printStackTrace();
    } finally {
    MyUtils.close(objectInputStream);
    }
    }
    }
    ).start();
    }

3. 使用 Messenger

4. 使用 AIDL

5. 使用 ContentProvider

6. 使用 Socket

-------------------- 本文结束感谢您的阅读 --------------------