###前言
共享文件也是一种不错的进程间通信方式,两个进程通过读/写同一个文件来交换数据,比如 A 进程把数据写入文件,B 进程通过读取这个文件来获取数据。
我们知道,在 Windows 上,一个文件如果被加了排斥锁将会导致其他线程无法对其进行其他访问,包括读和写,而由于 Android 系统基于 Linux,使得其并发读/写文件可以没有限制的进行,甚至两个线程可以同时对一个文件进行写操作都是允许的,尽管这可能会出问题。通过文件交换数据很好使用,除了可以交换一些文本信息外,我们还可以序列化一个对象到文件系统中的同时从另一个进程中恢复这个对象。
###使用文件共享
在 MainActivity 中的修改:
new Thread(new Runnable() {
@Override
public void run() {
User user = new User(1, "hello world");
File dir = new File(Environment.getExternalStorageDirectory().getPath()+"/shareFile");
if (!dir.exists()) {
dir.mkdirs();
}
File cachedFile = new File(Environment.getExternalStorageDirectory().getPath()+"/shareFile/usercache");
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 中读取:
new Thread(new Runnable() {
@Override
public void run() {
User user = null;
File cachedFile = new File(Environment.getExternalStorageDirectory().getPath()+"/shareFile/usercache");
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) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
MyUtils.close(objectInputStream);
}
}
}
}).start();
其中 MyUtils 工具类:
public class MyUtils{
public static void close(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
User 类:
public class User implements Serializable {
private static final long serialVersionUID = 519067123721295773L;
public int userId;
public String userName;
public User() {
}
public User(int userId, String userName) {
this.userId = userId;
this.userName = userName;
}
@Override
public String toString() {
return String.format(
"User:{userId:%s, userName:%s}",userId, userName);
}
}
注意:
在 SecondActivity 中成功从文件中恢复的之前存储的 User 对象是反序列化得到的对象,虽然内容跟之前的 User 对象一样,但跟序列化之前的 User 对象并不是同一个对象实体,本质上还是两个对象。
###总结
通过文件共享这种方式来共享数据对文件格式是没有具体要求的,比如可以是文本文件,也可以是 XML 文件,只要读/写双方约定数据格式即可。通过文件共享的方式也是有局限性的,比如并发读/写的问题,因此我们要尽量避免并发读/写情况的发生或者考虑使用线程同步来限制多个线程的读/写操作。
通过上面分析,我们知道,文件共享方式适合在对数据同步要求不高的进程之间进行通信,并且要妥善处理并发读/写的问题。
###补充
当然,SharedPreferences 是个特例,它是 Android 中提供的轻量级存储方案,它通过键值对的方式来存储数据,在底层实现上采用 XML 文件来存储键值对,每个应用的 SharedPreferences 文件都可以在当前包所在的 data 目录下查看到。一般来说,它的目录位于 /data/data/ 包名 /shared_prefs 目录下。
从本质上来说,SharedPreferences 也属于文件的一种,但是由于系统对它的读/写有一定的缓存策略,即在内存中会有一份 SharedPreferences 文件的缓存,因此在多进程模式下,系统对它的读/写就变得不可靠,当面对高并发的读/写访问,SharedPreferences 有很大几率丢失数据,因此,不建议在进程间通信中使用 SharedPreferences 。