本文为Android的IPC相关知识整理,具体参考了
- 《Android开发艺术探索》第二章 IPC机制
IPC,Inter-Process Communicatoin的缩写。即为Android进程间通信。
1,进程与线程
- 线程是CPU调度的基本单位,进程一般指一个执行单元,在移动设备上指一个应用或者是一个程序。一个进程包含一个或多个线程。
- 在Android中,一个程序可以只有一个线程,即主线程,也叫UI线程。在UI线程中才能操作界面元素,而不能在UI线程中执行大量耗时任务,否则会造成ANR,Application not responding错误。
Android线程(Thread)间通信:
- Handle和Looper配合,消息队列机制。我们可以用AsyncTask类这个异步任务类。
- 访问其他应用程序的Activity,通过Intent附带信息
IntentcallIntent= newIntent(Intent.ACTION_CALL,Uri.parse("tel:12345678");
startActivity(callIntent); - ContentProvider,例如访问系统相册,通讯录,短信等
- Broadcast 广播
- AIDL,Android接口定义语言
Android进程(Process)间通信:
- Binder
- Socket
- 文件共享
- ContentProvider
- Intent
- Messenger
2,Android中的多进程
在Android中使用多进程只有一种方法,即给四大组件在AndroidManifest中指定android:process属性。
<activity
android:name="com.ryg.chapter_2.MainActivity"
android:label="@string/app_name">
<intent-filter>
....
</intent-filter>
</acitivty>
<activity
android:name="com.ryg.chapter_2.SecondAcitvity"
android:process=":remote"/>
<activity
android:name="com.ryg.chapter_2.ThirdAcitvity"
android:process="com.ryg.chapter.remote"/>
以上三个activity分别在以下进程中:
- com.ryg.chapter_2,没有为组件指定process,那么这个组件就会运行在默认进程中。
- com.ryg.chapter_2:remote,冒号的含义是在当前的进程名上附加当前的包名,此进程属于当前应用的私有进程。
- com.ryg.chapter_2.remote,进程名不以冒号开头的进程属于全局进程,其他应用通过ShareUID方式可以和它跑在同一个进程中。
由于Android会为每一个进程提供单独的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,因而在不同的虚拟机中访问同一个类对象会产生多份副本。不同进程的虚拟机,Application,内存空间都不一样!!!!相当于两个不同的应用采用了SharedUID模式。
多进程引起的问题:
- 静态成员和单例模式失效
- 线程同步机制失效
- SharedPreferences可靠性下降,其不支持两个进程同时执行写操作。
- Application会多次重建
3,IPC基础概念
当我们需要通过Intent和Binder传输数据时,需要使用Serializable和Serializable接口来完成对象的序列化。
当我们需要使对象持久化到存储设备上时,需要使用Serializable来完成对象的持久化。
3.1 Serializable接口
这个是Java自带的,很简单但是内存开销大,只需要在类中加入serialVersionUID。适用于将对象序列化到存储设备或者将对象序列化后通过网络进行传输。
public class User implements Serializable{
private static final serialVersionUID = 4132904873290147032L;
public int userId;
public String userName;
public boolean isMale;
}
序列化和反序列化过程
//序列化
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();
恢复后的newUser对象和user内容完全一致,但不是同一对象。
为了避免反序列化失败,serialVersionUID 一般应该手动指定!!!其实也可以不指定serialVersionUID ,但这样的话是IDE自动根据类结构去生成hash值,这样的话我们对其的控制力就弱了,如果改变了类结构,就不能反序列化了!!!!而手动指定serialVersionUID 可以最大限度恢复数据。
3.2 Parcelable接口
这个是Android独有的,更适合用在Android平台,效率高,但是用起来有点麻烦。
public class User implements parcelable{
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;
}
public Book book;
//内容描述
public int describeContents(){
return 0;
}
//序列化
public void writeToParcel(Parcel out, int flags){
out.writeInt(userId);
out.writeString(userName);
out.writeInt(isMale ? 1 : 0);
out.writeParcelable(book, 0 );
}
//反序列化
public static final Parcelable.Creator<user> CREATOR = new Parcelable.Creator<User>(){
//从序列化后的对象中创建原始对象
public User createFromParcel(Parcel in){
return new User(in);
}
//创建指定长度的原始对象
public User[] newArray(int size){
return new User[size];
}
};
private User(Parcel in){
userId = in.readInt();
userName = in.readString();
isMale = in.readInt() = 1;
book = in.readParcelable(Thread.currentThread().getContextClassLoader());
}
}
3.3 Binder
- 从IPC角度看,Binder是一种跨进程通信方式。
- 从Android Freamwork角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager)和相应ManagerService的桥梁。
- 从Android应用层将,Binder是客户端和服务器进行通信的媒介。
Android开发中,Binder主要用在Service中,包括AIDL,Messenger。
网友评论