android 进程间数据共享,通过ContentProvider多进程共享SharedPreferences数据

  • Post author:
  • Post category:其他


转载注明出处:简书-十个雨点

开发一个多进程应用的时候,我们往往无法避免在多个进程之间共享数据。

多进程共享数据的方法有很多种,在Android中常用的有:SharedPreferences(多进程模式)、广播、Socket、ContentProvider、Messenger、AIDL等。这些方法适用于不同的使用场景,又有各自的局限性。

本文即将介绍的是通过ContentProvider,结合SharedPreferences(以下简称SP)实现的进程间共享设置项的功能。这种方式主要适用于以下场景:在一个进程中进行一些设置,而需要在另一个进程实时读取设置,并根据这些设置来执行功能。

1.SharedPreferences在多进程共享下的局限

有些同学可能会觉得奇怪:明明上面才说了SP(多进程模式)也是多进程共享数据的方法,为什么还需要通过ContentProvider来做呢。答案很简单,因为SP其实并不能保证多进程间同步,下图是关于MODE_MULTI_PROCESS的注释,我就不全文翻译了。

bdebf741221e

MODE_MULTI_PROCESS模式的注释

我们都知道,SP其实是将key-value对保存在手机的data/data/you.package.name/shared_prefs/目录下的文件中。为了减少IO造成的性能损失,SP使用了缓存的机制,会先把数据保存在内存中,在读取的时候直接从内存中读取,而写的时候才会保存到文件。也就是说普通SP是一次读取,多次写入的工作模式。所以如果多个进程中都使用了普通的SP,分别进行保存就会导致相互覆盖。而设置了MODE_MULTI_PROCESS之后,在多进程使用的时候,会在检测到文件变化的时候重新加载文件到内存中,这样虽然损失了一部分性能,但是却部分实现了多进程间同步。

为什么说是”部分”实现了多进程间同步呢?因为在频繁进行SP操作的时候,就还是会出现相互覆盖的问题。我初步估计是因为两个进程同时进行了文件的写操作,带着这个猜测我阅读了源码。

先看看对MODE_MULTI_PROCESS是如何处理的

ContextImpl的getSharedPreferences方法:

@Override

public SharedPreferences getSharedPreferences(File file, int mode) {

checkMode(mode);

SharedPreferencesImpl sp;

synchronized (ContextImpl.class) {

final ArrayMap cache = getSharedPreferencesCacheLocked();

sp = cache.get(file);

if (sp == null) {

sp = new SharedPreferencesImpl(file, mode);

cache.put(file, sp);

return sp;

}

}

if ((mode & Context.MODE_MULTI_PROCESS) != 0 ||

getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {

// If somebody else (some other process) changed the prefs

// file behind our back, we reload it. This has been the

// historical (if undocumented) behavior.

sp.startReloadIfChangedUnexpectedly();

}

return sp;

}

其中SharedPreferencesImpl的startReloadIfChangedUnexpectedly方法:

void startReloadIfChangedUnexpectedly() {

synchronized (this) {

// TODO: wait for any pending writes to disk?

if (!hasFileChangedUnexpectedly()) {

return;

}

startLoadFromDisk();

}

}

可见遇到MODE_MULTI_PROCESS的时候,会强制让SP进行一次读取操作,从而保证数据是最新的。因此如果你在外部保存了一份SP的对象,反而会导致享受不到MODE_MULTI_PROCESS带来的同步效果了,而且从源码中可以看出Cont