目录
Linux和Android的IPC机制:
IPC全称为Inter-Process Communication,含义为进程之间的通信,也就是两个进程之间进行数据交换的过程。在Android和Linux中都有自己的IPC机制。
1.Linux中的IPC机制:
Linux 中提供了很多进程间通信机制,主要有管道(Pipe)、信号(Sinal)、信号量(Semophore)、消息队列(Message)、共享内存(Share Memory)和套接字(Socket)等。
1.1:管道:
管道是Linux由UNIX继承过来的进程间的通信机制,它是UNIX早期的一个重要通信机制。管道的主要思想是在内存中创建一个共享文件,从而使通信双方利用这个共享文件来传递信息。这个共享文件比较特殊,它不属于文件系统并且只存在于内存中。另外,管道采用半双工通信方式,数据只能在一个方向上流动。
1.2:信号:
信号是软件层次上对中断机制的一种模拟,信号是一种异步通信方式,进程不必通过任何操作来等待信号的到达。信号可以在用户空间进程和内核之间直接交互,内核可以利用信号来通知用户空间的进程发生了哪些系统事件。信号不适用于信息交换,比较适用于进程中断控制。
1.3:信号量:
信号量是一个计数器,用来控制多个进程对共享资源的访问。信号量常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。信号量主要作为进程间及同一进程内不同线程之间的同步手段。
1.4:消息队列:
消息队列是消息的链表,具有特定的格式,消息队列存放在内存中由消息队列标识符进行标识,并且允许一个或多个进程向它写入与读取消息。使用消息队列会使信息复制两次,因此对于频繁通信或者信息量大的通信不宜使用消息队列。
1.5:共享内存:
共享内存的多个进程可以直接读写一块内存空间,是针对其他通信机制运行效率较低而设计的。为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间。这样,进程就可以直接读写这一块内存而不需要进行数据的复制,从而大幅度提高效率。
1.6:套接字:
套接字是更基础的进程间通信机制,与其他通信机制不同的是,套接字可用于不同机器之间的进程间通信。
2.Android中的IPC机制:
Android系统是基于Linux内核的,在Linux内核基础上又拓展出了一些IPC机制。Android 系统除了支持套接字,还支持序列化、Messenger、AIDL、Bundle、文件共享、ContentProvider和Binder等。
2.1:序列化:
序列化指的是Serializable/Parcelable接口,Serializable接口是Java提供的一个序列化接口,是一个空接口,为对象提供标准的序列化和反序列化操作。Parcelable接口是Android中的序列化方式,更适合在Android平台上使用。虽然Parcelable接口用起来比较麻烦,但是其效率很高。
2.2:Messenger:
Messenger在Android应用开发中的使用频率不高,可以在不同进程中传递Message对象,在Message中加入我们想要传递的数据就可以在进程间进行数据传递了。Messenger是一种轻量级的IPC方案,并对AIDL进行了封装。
2.3:AIDL:
AIDL全称为 Android Interface Definition Language,即Android 接口定义语言。Messenger是以串行的方式来处理客户端发来的信息的,如果有大量的消息发送到服务端,那么服务端仍然逐个处理再响应客户端显然是不合适的。虽然Messenger可以用于进程间数据传递,但是却不能满足跨进程的方法调用,这个时候就需要使用AIDL了。
2.4:Bundle:
Bundle实现了Parcelable接口,所以它可以在不同的进程间传输。Activity、Service、Receiver都是在Intent中通过Bundle来进行数据传递的。
2.5:文件共享:
两个进程通过读写同一个文件来进行数据共享,共享的文件可以是文本、XML,JSON。文件共享适用于对数据同步要求不高的进程间通信。
2.6:ContentProvider:
ContentProvider为存储和获取数据提供统一的接口,它可以在不同的应用程序之间共享数据,ContentProvider本身就是适合进程间通信的。ContentProvider底层实现也是 Bindr,但是使用起来比AIDL要容易许多。系统中很多操作都采用了ComtentProvider,例如通讯录、音视频等,这些操作本身就是跨进程进行通信的。
开启多进程:
既然要讲解Android应用开发中的IPC机制,那么就需要代码的示例,而这些示例都需要开启多进程。Android应用要开启多进程的原因,主要有以下几点:
- 单进程所分配的内存不够,需要更多的内存。早期的Android系统只为一个单进程的应用分配了16MB的可用内存,随着手机硬件的提升和Android系统的改进,虽然可分配内存越来越多,但仍旧可以通过开启多进程来获取更多内存来处理自己App的业务。
- 独立运行的组件,比如个推,它的服务会另开启一个进程。
- 运行一些“不可见人”的操作,比如获取用户的隐私数据,比如防止双守护进程被用户杀掉。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent myServiceIntent=new Intent(MainActivity.this,MyService.class);
this.startService(myServiceIntent);
}
}
public class MyService extends Service {
private static final String TAG="ssss";
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public int onStartCommand(Intent intent,int flags,int startId){
Log.i(TAG,"MainActivity is created");
return START_STICKY;
}
@Override
public void onDestroy(){
Log.i(TAG, "onDestroy ");
}
@Override
public void onCreate(){
Log.i(TAG, "onCreate");
}
}
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
tools:targetApi="31">
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"
android:process=":remote"></service>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
其中重要的是android:process属性,表示是否要开启一个新的进程运行,而后面的命名方式有两种,分别是:加冒号和不加冒号,其中加冒号的进程名,表示这个新的进程对这个应用来说是私有的,其他的应用组件不能和新的进程运行在同一个进程中。而不加冒号的,表示这个服务运行在以这个名字命名的全局的进程中,当然前提的有权限,将允许不同应用的组件运行在同一个进程中,从而减少资源的占用。注意:这种写法会导致Application会运行两次,两个进程都执行了oncreate方法。解决的办法是得到每个进程的名字,根据不同的进程进行不同的操作。