一、IPC机制
1.1、Android IPC简介
IPC是Inter-Process Communication的缩写,含义为进程间通信或跨进程通信,是两个进程间进行数据交换的过程。
什么是线程?什么是进程?
线程是CPU调度的最小单元,同时线程是一种有限的系统资源。进程一般指一个执行单元,在PC和移动设备上指一个程序或应用。
- 进程中包含了线程,所以他们是包含与被包含的关系。
- 一个进程可以只有一个线程,就是主线程。
Android的进程通信并非完全继承自Linux,相反它有自己的通信机制,通过Binder完成跨进程通信,同时也支持socket通信。
1.2、多进程模式
1、创建多进程的两种方式:
- 在清单文件中给四大组件设置android:process属性。
- 通过JNI在native层fork一个新的进程。
<activity android:name="cn.legend.remote.SecondActivity" android:process=":remote"> </activity> <activity android:name="cn.legend.remote.ThirdActivity" android:process="cn.legend.remote"> </activity>
上面为两个Activity设置process属性,但是值却不一样,下面分析下区别:
- :是简写方式,表示在前加上应用程序包名信息,它表示的是私有进程,其他组件无法运行在该进程中。
- 全包名的是一种完整的命名方式,不会附加包名信息,它表示的是全局进程。
Android系统会为每个应用分配UID,相同UID和签名相同的应用可以共享数据。
1.3、多进程模式的运行机制
我们在上面的示例中新建一个类UserManager,并在清单文件给SecondActivity配置process属性让其运行在一个独立进程中
public class UserManager { public static int mUserid = 1; }
在MainActivity中我们给该静态变量赋值为2并打印
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); UserManager.mUserid = 2; Log.w("MainActivity:","mUserid = " + UserManager.mUserid); }
当然我们在SecondActivity中也打印该变量
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); Log.w("SecondActivity:","mUserid = " + UserManager.mUserid); }
下面我们来看看运行后的结果:
Android会为每个进程分配不同的虚拟机,它们在内存分配上有不同的地址空间,导致在不同虚拟机访问同一个对象会产生多个副本。
而我们的例子中,其实两个进程中相当于有两个UserManager类,它们互不影响,所以也就解释了上面的问题。
使用多进程造成的如下问题:
- 静态成员和单例模式完全失效。
- 线程同步机制完全失效。
- SharePreferences的可靠性下降。
- Application会多次创建。
第一个问题和第二个问题本质上是相同的,都是不再同一块内存,而第三个问题是由于SharePreferences不支持两个进程同时读写,有几率丢失数据。
第四个问题是由于当有组件在新的进程中的时候,系统在创建新进程的同时分配独立的虚拟机,该过程其实是启动一个应用的过程。
二、IPC基础概念介绍
IPC机制主要包含三个方面:Serializable接口和Parcelable接口以及Binder。
Serializable和Parcelable接口可以完成对象的序列化过程,当我们需要用Intent和Binder传输数据时需要它们。
1.1、Serializable
Serializable是Java所提供的一个序列化接口,是一个标记接口,为对象提供标准的序列化和反序列化操作。
public class User implements Serializable{ private static final long serialVersionUID = 519067123721295773L; public int userid; public String userName; public boolean isMale; ... }
实现Serializable接口后我们就可以对对象进行序列化和反序列化了,我们也可以不声明UID,但是这会给反序列化带来麻烦。
/**序列化过程*/ User user = new User(0, "jake", true); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt")); out.writeObject(user); out.close(); /**反序列化过程*/ ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt")); User newUser = (User) in.readObject(); in.close();
其中,UID是和成员变量计算有关的,如果不指定UID的话,如果成员变量发生改变,反序列化时就会报错。
1.2、Parcelable
Parcelable也是一个接口,只要实现该接口,一个类的对象就可以实现序列化并可以通过Intent和Binder传递。
待续