1.Android跨进程通信
IPC是Inter-Process Communication的缩写,含义就是进程间通信或者跨进程通信,是指两个进程之间进行数据交互的过程。在说起进程间通信之前我们需要了解什么是进程,什么又是线程。在操作系统中线程指的是CPU调度的最小单元,同时在一个设备中线程是一种有限的系统资源。而进程一般指的是一个执行单元,在PC或者移动设备中指一个程序或者一个应用,因此一个进程可以包含多个线程,进程与线程之间是包含与被包含的关系。
2.Android中的多进程模式
说起使用IPC机制就必须要提到多进程,因为只有面对多进程的这种场景下才需要考虑使用进程间的通信。在Android中使用多进程的情况大致分为以下两种:
(1)应用因为某些原因需要采用多进程的模式来实现,至于原因可能有很多种,比如有些模块由于特殊原因需要单独运行在一个进程中,又或者一个应用需要使用更多的内存所以需要通过多进程来获取多份的内存空间。Android对单个应用所使用的最大内存做了限制,早期的一些版本可能是16MB,不同的设备有不同的大小。
(2)当前的应用需要向其它应用获取数据,由于是两个应用,所以必须采用跨进程的方式来获取所需的数据。
在同一个应用中我们只需要给四大组件指定android:process属性,就可以轻易的开启多进程模式,这看起来很简单但是在使用的过程中会出现各种各样的问题。在Android系统中每一个应用都会分配一个独立的虚拟机,或者说为每一个进程分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这就导致在不同的虚拟机中访问同一个类的对象会产生多个副本。所有运行在不同进程中的四大组件,只要它们之间需要通过内存来共享数据,都会共享失败,这也是多进行所带来的主要影响。一般的来说使用多进程会造成如下几个方面的问题:
(1)静态成员和单例模式完全失效
(2)线程同步机制完全失效
(3)SharedPreferences的可靠性下降
(4)Application会多次创建
3.AIDL是什么?
AIDL(Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。
4.在同一个应用中使用AIDL来进行不同进程间的通信
使用AIDL来进行进程间通信的流程,主要分为服务端和客户端两个方面
(1)服务端
服务端首先要创建一个Service用来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现这个AIDL接口即可。
(2)客户端
客户端首先要绑定服务端的Service,在绑定成功以后将服务端onBind()方法返回的Binder对象转成AIDL接口所属的类型,接下来就可以通过转成的AIDL接口所属的类型来调用AIDL其中的方法了。
因为我们此次所要传递的数据类型是一个对象,不是默认的数据类型,所以我们首先先要创建Book的类(Book.java),并且实现Parcelable接口
package com.example.administrator.aidldemo;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by ChuPeng on 2017/3/15.
*/
public class Book implements Parcelable
{
private String name;
private int price;
public Book()
{
}
protected Book(Parcel in)
{
name = in.readString();
price = in.readInt();
}
public void writeToParcel(Parcel dest, int flags)
{
dest.writeString(name);
dest.writeInt(price);
}
public int describeContents()
{
return 0;
}
public static final Creator<Book> CREATOR = new Creator<Book>()
{
public Book createFromParcel(Parcel in)
{
return new Book(in);
}
public Book[] newArray(int size)
{
return new Book[size];
}
};
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getPrice()
{
return price;
}
public void setPrice(int price)
{
this.price = price;
}
}
在AIDL文件中,不是所有的数据类型都是可以使用的,AIDL文件所支持的数据类型如下所示:
- 基本数据类型(int、long、char、boolean、double等)
- String和CharSequence
- List:只支持ArrayList,里面的每个元素的类型都必须能够被AIDL支持
- Map:只支持HashMap,里面的每个元素的类型都必须能够被AIDL支持,包括Key和value
- Parcelable:所有实现了Parcelable接口的对象
- AIDL:所有的AIDL接口本身也可以在AIDL文件中使用
在Android Studio中可以直接新建AIDL文件,入下图所示
其次我们需要创建AIDL文件(IBookManager.aidl),并且在里面声明一个接口和两个接口方法
// IBookManager.aidl
//第二类AIDL文件
//作用是定义方法接口
package com.example.administrator.aidldemo;
// Declare any non-default types here with import statements
// 声明任何非默认类型和导入语句
//导入所需要使用的非默认支持数据类型的包
import com.example.administrator.aidldemo.Book;
interface IBookManager
{
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
//所有的返回值前都不需要加任何东西,不管是什么数据类型
List<Book> getBooks();
Book getBook();
//传参时除了Java基本类型以及String,CharSequence之外的类型
//都需要在前面加上定向tag,具体加什么量需而定
void addBook(in Book book);
}
在IBookManager.aidl文件中由于使用了非默认支持的数据类型,因此需要通过使用import com.example.administrator.aidldemo.Book;来手动的导入上一步我们自己新建的Book.java,否则会在编译中报错。另外一个需要注意的地方是,如果AIDL文件中用到了自定义的Parcelable对象,那么必须新建一个和它同名的AIDL文件,并且在其中声明为parcelable类型(parcelable是小写),在上面的IBookManager.aidl中用到了Book.java的类,所以我们必须要创建Book.aidl。
除此之外,AIDL中除了基本数据类型,其它类型的参数必须标上方向:in、out或者inout,in表示输入型参数,out表示输出型参数,inout表