美文网首页首页投稿(暂停使用,暂停投稿)
深入理解Android-理解IPC机制(1 - 理解多进程)

深入理解Android-理解IPC机制(1 - 理解多进程)

作者: 289346a467da | 来源:发表于2017-07-15 14:18 被阅读1247次

    原创 2017-07-15 认真的 小苏
    文章中的代码

    技术前沿

    下载.jpg

    Android之神"JakeWharton"要离职!!!
    周末无聊刷twitter 看到JakeWharton说要离开Square公司了

    image.png

    大致意思就是:五年半后,今天是@Square的最后一天。转移到另一种乐趣!
    我们熟知的OkHttp,Retorfit,ButterKnife,RxAndroid,RxBinding都是他的大作。

    先来一个段子

    到现在为止,世界上不得不承认的七个事实,请别吃惊。 01.你的脖子转不了两圈。 2.你数不了你有多少头发。 3.当你舌头伸出来的时候你不能用鼻子呼吸。 4.你正在做第三条。 5.当你在做第三条的时候,其实你觉得是可行的,但是你看起来会像条小狗一样。 6.你现在在笑,因为我把你整了。 7,被整到的请点喜欢,不许耍赖。

    思考

    IPC 不是Android独有的,任何一个操作系统都有相应的IPC机制,比如Windows,Linux,IOS 都存在的IPC机制,这里不介绍其他的,只介绍Android的 具体的实现,众所周知android 是一种基于Linux内核动一动操作系统,但进程间的通信并没有完全集成Linux,深入了解IPC 对我们学习其他语言都有帮助,编程最重要的就是思想,编程思想在了,那么不管学习任何语言都很轻松就能学会,任何语言都有它的发展趋势,至少在有生之年Android是不会被取代的,Android现在已趋于稳定,正在一步一步完善中,不要听别人的长篇大论,做好当下的事,处理好眼下的BUG,不要想其他的,随着经验的增长,你会逐渐发现一个语言的魅力,你的能力也会越来越出众,额...貌似越扯越远了,不说了进入正题。

    IPC 浅析 以及所带来的问题

    IPC 全称:Inter-Process Communication 意思是:进程间的通信,是指两个进程之间进行数据交换的过程。

    什么是进程: 进程一般指一个执行单元,设备上的一个程序或者一个应用,一个进程可以包含多个线程,可以这样理解就相当于一个应用Application,最简单会有一个UI线程即主线程,还有一个后台线程来请求网络数据。

    什么是线程: 线程是CPU调度的最小单元,同时也是一种有限的系统资源,一般耗时的任务都会放到线程中去处理。(具体线程的概念在下一篇文章中讲解)

    IPC 使用的场景,什么情况下我们会用到多进程间的通信呢?

    比如说有一些模块因为特殊原因需要运行在单独进程中,我们常用到的第三方的sdk,极光推送,即时通讯等。
    比如说为了加大一个应用的内存需要多进程来获取多个内存空间,Android对单个应用的最大内存做了限制,这样我们就可以运用多进程的方式来减少内存溢出的问题,常见的一些新闻软件,详情页就是用WebView来实现的,但是占用内存特别大,就可以用多进程的方式来有效的减少内存溢出 。
    另一种情况就是当另一个应用需要向其他应用获取数据,就必须用到跨进程通信,常见的通讯录软件,就需要通过ContentProvider 查询数据。

    进程间通讯的方式: 通过Intent 传递Bundle、文件 Flies 共享 比如:一个进程将数据存储为一个txt文件,存到SD卡中,另一个进程读取SD的目录 获取数据 也可以修改数据、AIDL 、Messenger、ContentProvider、Socket 等

    通过上述描述,大致了解了多进程和多进程之间的通讯方式,下面我们讲解如何在Android中开启多进程模式

    开启多进程很简单,我们只需要给四大组件(Activity、Service、Receiver、ContentProvider)在AndroidMenifest 中指定 android:process 属性即可


    image.png

    新建两个项目创建两个Activity 分别设置它的process属性值,需要值得注意的是process属性值有两种命名方式:

    1. 进程名以":"开头的进程属于当前应用的私有进程,进程名为 包名:XXX 其他应用组件不能和他跑在同一个进程中。
    2. com.XXX.XXX 属于全局进程,其他应用可以通过UID方式和它跑在同一个进程中。
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="ipctest.linksu.com.androidipc">
    
        <application
            android:allowBackup="true"
            android:name=".MyApp"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            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=".Ipc1Activity"
                android:process=":remote" />
            <activity
                android:name=".Ipc2Activity"
                android:process="com.linksu.ipctest.remote" />
        </application>
    
    </manifest>
    

    运行项目

    image.png

    然后打开Android Deverice Monitor


    image.png

    可以看到我们新建项目的包名,这就是这个应用的进程

    image.png

    然后我们点击 IPC1、IPC2 两个按钮分别启动Ipc1Activity Ipc2Activity,然后再打开Android Deverice Monitor,我们就可以看到新开的两个进程了

    image.png

    OK,开启进程就是这么简单,但是最主要的就是我们如何进行进程间的通信,数据同步,有人说创建一个public的静态的成员变量不就可以了吗,NO 但是事实并非如此,没有那么简单。

    听我细细道来,不同的进程中的组件是属于两个不同的虚拟机和Application的。也就是说每开启一个进程就会重新启动一个虚拟机。

    我们可以做一个测试,在Application的onCreate方法中,我们打印一个log

     @Override
        public void onCreate() {
            super.onCreate();
            Log.e("Application", "onCreate: process name -->" + getProcessName());
        }
    
        public String getProcessName() {
            int pid = android.os.Process.myPid();//获取进程pid
            String processName = "";
            ActivityManager am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);//获取系统的ActivityManager服务
            for (ActivityManager.RunningAppProcessInfo appProcess : am.getRunningAppProcesses()) {
                if (appProcess.pid == pid) {
                    processName = appProcess.processName;
                    break;
                }
            }
            return processName;
        }
    

    上述代码很简单将当前应用的进程名打印出来,运行项目,点击IPC1和IPC2按钮,看log

    Application: onCreate: process name -->ipctest.linksu.com.androidipc
    Application: onCreate: process name -->ipctest.linksu.com.androidipc:remote
    Application: onCreate: process name -->com.linksu.ipctest.remote
    

    Application 执行了三次onCreate,可以看出先执行了,应用本身的进程,然后IPC1 IPC2 ,也就证实了,不同的进程组件拥有独立的虚拟机、Application以及内存空间,直观的理解相当于两个应用不同的UID。

    我们再写一个Dome 进一步证实,静态变量是否可以在多进程中共享。
    依据上面的代码,我们创建一个Constant 存储静态变量的类

    public class Constant {
        public static int processData = 0;
    }
    

    在MainActivity 中赋值为2,在Ipc1Activity Ipc2Activity,中打印processData,看看这个值是否变了

    Log.d("Ipc1Activity", "processData :" + Constant .processData );
    

    按照正常的逻辑来说静态变量存在内存中,是可以在所有地方共享的,我们运行项目,点击IPC1 和IPC2 按钮,看一下结果

    MainActivity: processData :2
    
    Ipc2Activity: processData :0
    
    Ipc1Activity: processData :0
    
    

    从上述中,我们可以得出结论:每个进程都会有一个独立的虚拟机,每个虚拟机都会重新分配内存,所以说不同进程中,存在内存中的数据是互不干扰的,对其他进程不会造成任何影响。

    多进程造成的问题:
    1、静态成员变量、单例模式等凡是存在内存中的数据完全失效
    2、Application 会创建多次
    3、线程同步完全失效

    我们可以在试一下 SharedPreferences 看看是否完全失效,我们在MainActivity 中写如下代码

            SharedPreferences settings = getSharedPreferences("setting", 0);
    //2、让setting处于编辑状态
            SharedPreferences.Editor editor = settings.edit();
    //3、存放数据
            editor.putString("name", "IPC");
    //4、完成提交
            editor.commit();
    

    然后在Ipc1Activity 中读取数据

      //1、获取Preferences
            SharedPreferences settings = getSharedPreferences("setting", 0);
    //2、取出数据
            String name = settings.getString("name", "默认值");
            Log.d("Ipc1Activity", "name:" + name);
    

    运行项目 我们看一下log

    D/Ipc1Activity: name:IPC
    

    数据同步过来了,但是SharedPreference 不支持两个进程同时去执行写操作,否则会导致一定几率的数据丢失。

    这一篇文章我们只讲解,多进程的基本概念和启动模式、带来的那些问题,下一篇文章我们讲解,如何实现进程间的通信,Binder的深入理解 持续更新中,您的关注就是我的动力。
    深入理解IPC机制 2

    推荐 好用的翻墙工具

    参考:Android 开发艺术探索 及项目中的一些经验


    198750-106.jpg

    相关文章

      网友评论

        本文标题:深入理解Android-理解IPC机制(1 - 理解多进程)

        本文链接:https://www.haomeiwen.com/subject/gnrahxtx.html