共享文件也是一种不错的IPC方式,两个进程通过读写同一个文件来交换数据,比如A进程把数据写入文件,B进程通过读取文件来获取数据。由于Android基于Linux,所以并发读写没有什么限制,甚至线程同时读写文件都可以,尽管会出现问题。利用这个思想,我们可以序列化一个对象到文件系统中,同时另一个进程中回复这个对象。
还是以上一个工程为例:
在MainActivity添加以下代码:
1. @Override
2. protected void onResume() {
3. persistToFile();
4. super.onStart();
5. }
6.
7. private void persistToFile() {
8. new Thread(new Runnable() {
9.
10. @Override
11. public void run() {
12. String path = Environment.getExternalStorageDirectory().getPath()
13. "/qian/";
14. new User(1, "hello world", false);
15. new File(path);
16. if (!dir.exists()) {
17. dir.mkdirs();
18. }
19. new File(path + "cache");
20. null;
21. try {
22. new ObjectOutputStream(
23. new FileOutputStream(cachedFile));
24. objectOutputStream.writeObject(user);
25. "persist user:" + user);
26. catch (IOException e) {
27. e.printStackTrace();
28. finally {
29.
30.
31. try {
32. if(objectOutputStream != null)
33. objectOutputStream.close();
34. catch (IOException e) {
35. e.printStackTrace();
36. }
37.
38.
39. }
40. }
41. }).start();
42. }
在BundleActivty添加如下代码:
1. @Override
2. protected void onResume() {
3. super.onResume();
4. // User user = (User) getIntent().getSerializableExtra("extra_user");
5. "onResume");
6. recoverFromFile();
7. }
8.
9. private void recoverFromFile() {
10. new Thread(new Runnable() {
11.
12. @Override
13. public void run() {
14. null;
15. String path = Environment.getExternalStorageDirectory().getPath()
16. "/qian/";
17. new File(path + "cache");
18. if (cachedFile.exists()) {
19. null;
20. try {
21. new ObjectInputStream(
22. new FileInputStream(cachedFile));
23. user = (User) objectInputStream.readObject();
24. "recover user:" + user);
25. catch (IOException e) {
26. e.printStackTrace();
27. catch (ClassNotFoundException e) {
28. e.printStackTrace();
29. finally {
30. try {
31. if(objectInputStream != null)
32. objectInputStream.close();
33. catch (IOException e) {
34. e.printStackTrace();
35. }
36. }
37. }
38. }
39. }).start();
40.
其实一个序列化与反序列化的过程,其中定义了一个可序列化的对象User,继承自Parcelable, Serializable接口,这样便可以序列化,User代码如下:
1. package com.qian.ipc;
2.
3. import java.io.Serializable;
4.
5.
6.
7. import android.os.Parcel;
8. import android.os.Parcelable;
9.
10. public class User implements Parcelable, Serializable {
11. private static final long serialVersionUID = 519067123721295773L;
12.
13. public int userId;
14. public String userName;
15. public boolean isMale;
16.
17. public Book book;
18.
19. public User() {
20. }
21.
22. public User(int userId, String userName, boolean isMale) {
23. this.userId = userId;
24. this.userName = userName;
25. this.isMale = isMale;
26. }
27.
28. public int describeContents() {
29. return 0;
30. }
31.
32. public void writeToParcel(Parcel out, int flags) {
33. out.writeInt(userId);
34. out.writeString(userName);
35. 1 : 0);
36. 0);
37. }
38.
39. public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {
40. public User createFromParcel(Parcel in) {
41. return new User(in);
42. }
43.
44. public User[] newArray(int size) {
45. return new User[size];
46. }
47. };
48.
49. private User(Parcel in) {
50. userId = in.readInt();
51. userName = in.readString();
52. 1;
53. book = in
54. .readParcelable(Thread.currentThread().getContextClassLoader());
55. }
56.
57. @Override
58. public String toString() {
59. return String.format(
60. "User:{userId:%s, userName:%s, isMale:%s}, with child:{%s}",
61. userId, userName, isMale, book);
62. }
63.
64. }
最终打印的Log如下:只要红色框圈住的,其中红色框中第二栏Application打印的是进程名,可以看出MainActivity和BundleActivity是属于不同进程的。很显然,BundleActivity成功的从文件中回复了之前存储的User对象的内容,这里之所以说内容,是因为反序列化得到的对象只是在内容上和序列化之前的对象式样的,但他们本质上是两个对象。
通过文件共享这种方式来共享数据对文件格式是没有具体要求的,比如可以是文本文件,也可以是xml文件,只要读写双方约定数据格式即可,也不一定要用序列化对象这种方式来实现文件共享,但是问题是要处理并发读写的问题。
另外SharePreferences是个特例,它是Android中提供的轻量级存储方案,通过键值对的方式存储数据,在底层实现上采用xml文件来存储键值对。但是SharePreferences也有一个问题,但是由于系统对SharePreferences的读写有一定的缓存策略,也就是说在内存中会有一份SharePreferences文件的缓存,因此在多进程模式下,系统对它的读写就变得不可靠,当面对高并发的读写访问SharePreferences有很大几率会丢失数据。