赞
踩
IPC是Inter-Process Communication的简写,意为进程间通信或者跨进程间通信,是指两个进程间进行数据交换的过程。在说道进程间通信,首先,我们要理解什么是进程?什么线程?进程跟线程的关系又是什么?搞清楚这些东西,对我们来说,是很有必要的,当然了,这个进程与线程的关系,你们肯定是知道的,但是我还是要在这里啰嗦两句,哈哈,不要喷我啊。首先来说,什么是线程?线程其实就是程序中单独执行的流控制。那么什么又是多线程呢?那么他呢其实就是单个程序中,可以同时运行多个不同线程执行不同的任务。多线的作用就是最大限度的使用CPU资源。而进程呢?一般指的是一个执行单元。比如:一个程序或者在Android上来说,它是一个应用。进程可以有多个线程,所以说,进程与线程是包含与被包含的关系。
那么我们为什么要知道这个多进程呢?多进程对我们来说又有什么好处呢?这个多进程的使用场景很多,我们知道在Android早些时候的版本,每个应用分配的内存大小是16MB,有时候,我为了解决这个应用内存大小的问题,我就采用了多进程来解决这个内存不足的问题。当然,还有很多使用场景,比如说还有我们比较常见的跨进程通讯,ContentProvider对吧,他也是一种跨进程通信。好了,既然说到了多进程,那么我们下面就来说说如何开启多进程?当然开启多进程很简单,我们给四大组件定义一个process属性,就好了。但是,开启多进程对我们来说真的很简单吗?答案是否定的,如果多进程应用的不好,那就犹如黄河之水泛滥一发不可收拾。如果控制的不好,将会给你的程序带来灾难性的后果。下面我们来看个例子,然后来分析分析,在开启多进程之后会带来那些问题。如下:
我们在清单文件里配置,如下:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest
- package="com.example.ipcdemo"
- xmlns:android="http://schemas.android.com/apk/res/android">
-
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:name=".MyApplication"
- android:theme="@style/AppTheme">
- <activity android:name=".MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
-
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- <activity
- android:name=".SencondActivity"
- android:label="@string/app_name"
- android:process=":remote">
- </activity>
- <activity
- android:name=".ThirdActivity"
- android:label="@string/app_name"
- android:process="com.example.ipcdemo.remote">
- </activity>
- </application>
-
- </manifest>
好,现在我们运行一下程序,看看:
在上面的清单文件中,我们会发现,我们SencondActivity与ThirdActivity所声明的process方式是不一样的?一个是“ :remote”,一个是加上全部包名,“com.example.ipcdemo.remote”,那么他们之间有什么区别呢?当然是有区别的,对于,ThirdActivity中的声明方式,它是一个i额完整的声明方式,并且它不会附加包名信息,而SencondActivity则会附加包名信息。如果是以“:”开头的进程属于当前应用的私有进程,其他应用组件不可以和它跑到一个进程里,如果不是以“:”开头的进程属于全局的进程,其他的应用可以通过ShareUID可以和它跑到同一进程当中,我们知道Android系统会为每个应用分配一个唯一的UID,相同应用的UID的应用才能共享数据。但是这里要讲明的是,如果两个应用通过SharedUID跑到同一个进程中需要这两个应用的SharedUID相同并且签名也要相同才可以。当然,在这种情况下,他们可以互相访问对方的私有数据,比如:data目录,组件信息等,不管它们是否是跑在同一个进程当中,还有就是它们如果跑在同一个进程当中的话,除了能访问data目下、组件信息,还可以共享内存信息。
之前我们说道,开启多进程,会出现各种奇奇怪怪的问题,那么下面我们就来看一下这个例子,比如我们创建一个UserManger类,里面声明userId,int类型的:
- /**
- * Author : Created by rookie
- */
- public class UserManager {
-
- public static int sUserId = 1;
-
- }
接下来,我们在MainActivity里,修改这个值,然后在打印,接着在SecondActivity里打印一下userId的值,看看他是不是我们之前在MainActivity里面改过来的数据。代码如下:
- //MainActivity:
- public class MainActivity extends AppCompatActivity {
-
-
- private static final String TAG = "MainActivity";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- UserManager.sUserId = 2;
-
- Log.d(TAG,"sUserId = "+UserManager.sUserId);
-
-
- Intent intent = new Intent(this,SencondActivity.class);
- startActivity(intent);
-
- }
- }
-
-
- //SencondActivity:
- public class SencondActivity extends AppCompatActivity {
-
- private static final String TAG = "SencondActivity";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_sencond);
-
-
- Log.d(TAG, "sUserId = " + UserManager.sUserId);
- Intent intent = new Intent(this,ThirdActivity.class);
- startActivity(intent);
-
-
- }
- }
-
又上图可知,他们打印出来的值居然不一样,我们明明在MainActivity里改了,可是值在SedondActivity里打印出来并没有发生改变,这又是为什么呢?我们带着这个问题,来分析解答一下:
出现上述问题的原因很简单,那就是Android为我们每个应用都分配一个独立的虚拟机,或者你也可以这么去理解,Android系统为我们每个进程都分配了一个独立的虚拟机,不同的虚拟机将导致分配的内存空间也不一样,这也就是,在开启多进程的时候,每个进程对应一个独立的虚拟机,并且在访问同一个类的对象时,会产生多个副本。就拿这个例子来说吧,SedondActivity和ThirdActivity这两个进程中都会存在一个UserManger类,并且这两个类还是互不干扰的,那么你在前者的进程中修改值,在后一个进程中是不会收到影响的。这只是其中一种,那么我们在使用多进程的时候,他可能还会带来以下几个问题:
1>静态成员和单例模式完全失效。
2>线程同步机制完全失效。
3>SPreferences的可靠性下降。
4>Application会创建多次。
第一、第二个问题,类似,既然都不在同一个内存块了,无论你是锁对象还是所类都将无法保证线程同步,因为不同进程锁的对象不同。第三个问题,它不支持两个进程同时进行读写操作,否则会导致数据一定机率的丢失,好,到了第四个问题,我们创建一个Applictaion的子类来测试一下,代码如下:
- public class MyApplication extends Application {
-
-
- private static final String TAG = "MyApplication";
-
- @Override
- public void onCreate() {
- super.onCreate();
-
-
- Log.d(TAG,"进程名字 : "+ Utils.getProcessName(getApplicationContext(),android.os.Process.myPid()));
-
-
-
- }
- }
工具类:
- public class Utils {
-
-
- public static String getProcessName(Context context,int processId){
-
- ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-
- for(ActivityManager.RunningAppProcessInfo appProcess : am.getRunningAppProcesses()){
- if(appProcess.pid == processId){
- return appProcess.processName;
- }
- }
-
- return null;
- }
-
-
- }
运行效果:
从上面的结果,我们可以证实,不同进程的组件的确会拥有独立的虚拟机、Application以及内存空间,对吧,这也无形给我们日常开发中带来非常大的困扰,这篇我们说了,在使用多进程时所带来的问题,既然有问题,我们不能视若无睹,当然要想办法去解决,当然,Android系统,为我们提供很多跨进程的通信方式,虽然不能直接共享内存,但是交换数据还是没问题的。那么通信方式有哪些呢?这里可以预告一下,我们将会在下一篇讲到。比如:Intent来传递数据,共享文件和SharedPreferences,基于Binder的Messager和AIDL以及Socket,当然还有内容提供者(ContentProvider),但是,为了让我们更好的理解IPC的通信方式,我们要熟悉一些基础概念,比如:Serializable和Parcelable接口,以及Binder概念。我们将会在下一篇讲到这些基础概念,以及一种IPC机制通信方式。未完待续......
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。