文件共享是一种非常不错的IPC方式,即两个进程可以通过读/写同一个文件来交换数据。和Windows系统不同,Android系统是基于Linux的,这使得并发读/写文件的操作可以没有限制地进行,甚至两个线程同时对一个文件进行读/写也是可以的(尽管这样可能会出问题)。

  使用文件共享的方式实现IPC时,文件中除了可以存储一些文本信息外,我们也可以序列化一个对象到文件系统中,然后在另一个进程中恢复这个对象。

  下面用一个例子来演示在文件系统中读/写对象的功能。

  我们在一个Module中创建两个Activity,分别是MainActivity和SecondActivity,Manifest文件中的代码如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="my.itgungnir.ipc"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"></activity>
<activity
android:name=".SecondActivity"
android:process=":remote">
<intent-filter>
<action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application> </manifest>

  我们通过在SecondActivity中设置 android:process 属性,让SecondActivity运行在另一个进程中,然后通过控制 <intent-filter> 标签的位置来决定当前启动哪个Activity(即哪个进程)。

  另外,不要忘记在Manifest文件中添加访问SD卡的权限。

  在这个例子中,我们将一个User对象存储到文件中,我们首先需要对User类进行序列化,以保证能够在进程中传递,User类中的代码如下:

public class User implements Serializable {
private static final long serialVersionUID = 1L; public int userId;
public String userName;
public boolean isMale; public User(int userId, String userName, boolean isMale) {
this.userId = userId;
this.userName = userName;
this.isMale = isMale;
}
}

  需要注意的是,将对象存储到文件系统中的过程可以理解为持久化的过程,而Parcelable接口不适合用来序列化可持久化的数据,因此这个我们必须使用Serializable接口进行序列化。

  在MainActivity中有一个按钮,当点击这个按钮的时候,就会生成一个User类的对象,存储到设备的SD卡中,代码如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.a_btn);
btn.setOnClickListener(this);
} @Override
public void onClick(View v) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
} @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
new Thread(new Runnable() {
@Override
public void run() {
User user = new User(1001, "Alice", false);
String sdCardState = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(sdCardState)) {
File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/file_ipc/");
if (!dir.exists()) {
dir.mkdirs();
}
File tmpFile = new File(dir + File.separator + "fileipc.txt");
if (tmpFile.exists()) {
tmpFile.delete();
}
File file = new File(dir + File.separator + "fileipc.txt");
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(user);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}).start();
}
}

  需要说明的是,笔者做这个DEMO使用的是Android 6.0的SDK,因此在涉及到权限的时候,除了在Manifest文件中声明权限之外,还在在Activity中通过 ActivityCompat.requestPermissions() 方法申请权限,然后在 onRequestPermissionsResult() 方法中回调要执行的代码。

  通过运行项目(此时 <intent-filter> 标签在MainActivity下),User对象就被存储到SD卡的文件系统中了。

  SecondActivity中有一个TextView,用来显示从SD卡的文件系统中读取出来的User对象中的数据。SecondActivity中的代码如下:

public class SecondActivity extends AppCompatActivity {
private TextView tv; private Handler textHandler; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
tv = (TextView) findViewById(R.id.b_tv);
initHandler();
initView();
} private void initHandler() {
textHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
User user = (User) msg.obj;
tv.setText("读取文件成功!\r\n");
tv.append("用户编号:" + user.userId + "\r\n");
tv.append("用户姓名:" + user.userName + "\r\n");
tv.append("用户性别:" + (user.isMale ? "男" : "女") + "\r\n");
}
}
};
} private void initView() {
ActivityCompat.requestPermissions(SecondActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
} @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
new Thread(new Runnable() {
@Override
public void run() {
User user = null;
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "file_ipc" + File.separator + "fileipc.txt");
if (file.exists()) {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(file));
user = (User) ois.readObject();
Message msg = Message.obtain();
msg.what = 1;
msg.obj = user;
textHandler.sendMessage(msg);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}).start();
}
}

  注意:由于我们的读写操作都是耗时操作,因此我们新开了一个现成执行这些代码,因此当我们需要将读取到的数据展示到TextView中的时候,就需要使用Handler将数据传送到主线程中,再跟新UI界面。

  在Manifest文件中将 <intent-filter> 标签移动到SecondActivity下,再次运行项目,就可以看到SD卡中存储的User对象中的信息就被展示到TextView中了。

  最后,注意一点,SharedPreferences虽然也是以文件的形式存储数据的,但是不适合在IPC中使用,原因是Android系统对SharedPreferences的读/写有一定的缓存策略,即在内存中会有一份SharedPreferences文件的缓存,因此在多进程的模式下,系统对SharedPreferences的读写就变得不可靠,当面对高并发的读/写访问时,SharedPreferences有很大几率会丢失数据,因此,不建议在IPC中使用SharedPreferences。

【Android - IPC】之使用文件共享实现IPC的更多相关文章

  1. android service 的各种用法(IPC、AIDL)

    http://my.oschina.net/mopidick/blog/132325 最近在学android service,感觉终于把service的各种使用场景和用到的技术整理得比较明白了,受益颇 ...

  2. Android AIDL 进行进程间通讯(IPC)

    编写AIDL文件时,需要注意: 1.接口名和aidl文件名相同. 2.接口和方法前不用加访问权限修饰符 (public.private.protected等,也不能用final.static). 3. ...

  3. Android AIDL使用详解_Android IPC 机制详解

    一.概述 AIDL 意思即 Android Interface Definition Language,翻译过来就是Android接口定义语言,是用于定义服务器和客户端通信接口的一种描述语言,可以拿来 ...

  4. Linux IPC实践(13) --System V IPC综合实践

    实践:实现一个先进先出的共享内存shmfifo 使用消息队列即可实现消息的先进先出(FIFO), 但是使用共享内存实现消息的先进先出则更加快速; 我们首先完成C语言版本的shmfifo(基于过程调用) ...

  5. Android IPC机制全解析<一>

    概要 多进程概念及多进程常见注意事项 IPC基础:Android序列化和Binder 跨进程常见的几种通信方式:Bundle通过Intent传递数据,文件共享,ContentProvider,基于Bi ...

  6. Android IPC机制基础

    概要 多进程概念及多进程常见注意事项 IPC基础:Android序列化和Binder 跨进程常见的几种通信方式:Bundle通过Intent传递数据,文件共享,ContentProvider,基于Bi ...

  7. Android进阶笔记18:选用合适的IPC方式

    1. 相信大家都知道Android进程间通信方式很多,比如AIDL.Messenger等等,接下来我就总结一下这些IPC方式优缺点. 2. IPC方式的优缺点和适用场景 3. 附加:使用Intent实 ...

  8. [置顶] 深入理解android之IPC机制与Binder框架

    [android之IPC机制与Binder框架] [Binder框架.Parcel.Proxy-Stub以及AIDL] Abstract [每个平台都会有自己一套跨进程的IPC机制,让不同进程里的两个 ...

  9. Android IPC 结篇

    一.概述 Android 的 IPC 方式有 Bundle .共享文件.AIDL .Messenger .ContentProvider .Socket ,我们在实现进程间通信时要选择哪一种方式来实现 ...

随机推荐

  1. 卷积神经网络详细讲解 及 Tensorflow实现

    [附上个人git完整代码地址:https://github.com/Liuyubao/Tensorflow-CNN] [如有疑问,更进一步交流请留言或联系微信:523331232] Reference ...

  2. VS运行遇到的那些坑

    今天运行VS项目好好的,就是安装了VS2019后,就出现了无法连接到IIS服务器,这个问题,然后各种办法都试了无效. 解决方法: 1.删除根目录的.vs文件,然后重新生成. 2.修改调试这里的IP改为 ...

  3. vue学习笔记-遗留问题记录

    Node.js是什么?对node.js的理解 官网解释:Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时. 这是一种通过JavaScript语言开发web服务端的东 ...

  4. opacity层叠问题

    使用了position属性值为 absolute.relative 的层,将会比普通层更高层次.使用了小于1的opacity属性的层,也比普通层更高层次并且和指定 position 的层同层,但是不支 ...

  5. [Java]Java类和对象内存分配详解

    描述 代码说明: 一.当Person p1 = new Person();第一次被调用时需要做两件事: 1.先判断类加载器是否加载过Person类,如果没有则加载到Person类型到方法区 2.在堆中 ...

  6. [考试反思]1101csp-s模拟测试97:人品

    上来粘6个图皮一下.(以后粘排行榜是不是都应该粘两份啊...文件出入的确挺难受的) 话说最近RP为什么会这么高啊???我干什么好事了???不知道. 这次考试的题挺有水准的,但是我的分数挺没水准的. T ...

  7. CSPS模拟 88

    今天我还是个弟弟. 果然唯有AK不可超越.. T1 决策单调性,暴力上整体二分. 极限数据跑的挺快,可是被n<k的脑残测试点qj了.. T2 又是大模拟! T3 想到剩余同种数量的彩球完全等效 ...

  8. 浅谈 KMP 算法

    最近在复习数据结构,学到了 KMP 算法这一章,似乎又迷糊了,记得第一次学习这个算法时,老师在课堂上讲得唾沫横飞,十分有激情,而我们在下面听得一脸懵比,啥?这是个啥算法?啥玩意?再去看看书,完全听不懂 ...

  9. etcd-operator快速入门完全教程

    Operator是指一类基于Kubernetes自定义资源对象(CRD)和控制器(Controller)的云原生拓展服务,其中CRD定义了每个operator所创建和管理的自定义资源对象,Contro ...

  10. 【Java】面向对象之封装

    面向对象编程是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改.封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问.要访问该类的数据,必须通过指定的方式 ...