• Android:多进程的开启方式、注意点以及如何解决。


    前言

    线程是CPU调度的最小单元。而进程一般指一个执行单元,在PC和移动设备上指一个程序或者一个应用。一个进程可以包含多个线程,进程和线程是包含与被包含的关系。
    在很多中情况下我们需要开启多进程,最常见的比如某一个模块会占用很多的内存且比较独立,可以考虑放到单独的进程去处理。
    但是多进程不仅仅是简单指定一个进程名称就好了,下面会进行详细介绍。

    多进程的开启方式

    Android中开启多进程常规的话只有一种方式,给四大组件(ActivityServiceReceiverContentProvider)在AndroidMenifest中指定android:process属性。除此之外还有另一种非常规的方法,就是通过JNInative层去fork一个新的进程。

    常规来说都是在AndroidMenifest中指定android:process来开启多进程,可以看下面的示例。

    <activity
        android:name=".view.ClientActivity1"
        android:process=":client1" />
    
    <activity
        android:name=".view.ClientActivity2"
        android:process="com.howie.client.client2" />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    当前的应用包名为com.howie.multiple_process

    所以当应用启动之后:

    • 应用的默认进程即为com.howie.multiple_process
    • 当启动ClientActivity1之后,会启动一个名为com.howie.multiple_process:client1的进程;
    • 当启动ClientActivity2之后,会启动一个名为com.howie.client.client2的进程;

    可以运行程序看一下效果,利用AndroidStudioLogcat查看当前应用的进程数。

    在这里插入图片描述

    也可以利用adb shellps命令搜索匹配进程,比如我们输入adb shell "ps | grep com.howie",会打印出如下信息。

    u0_a428       9555  1042 14592908 101172 0                  0 S com.howie.multiple_process
    u0_a428       9690  1042 14608640 95004 0                   0 S com.howie.multiple_process:client1
    u0_a428       9728  1042 14608640 95724 0                   0 S com.howie.client.client2
    
    • 1
    • 2
    • 3

    需要注意的是,ClientActivity1ClientActivity2android:process属性值分别为:client1com.howie.client.client2

    这两种命名如下两个区别:

    1. 进程名字不同,:的进程名字为当前的进程名前附加上包名。如上所示,ClientActivity1的包名即为com.howie.multiple_process:client1;
    2. 进程名以:开头的话代表当前进程是应用程序的私有进程,其他应用的组件不可以和它跑在同一个进程;而不以:启动的进程属于全局进程,其他应用进程可以通过共享UID方式可以和它泡在同一个进程当中。两个应用通过ShareUID跑在同一个进程下需要相同的签名,此时可以互相访问对方的私有数据、还可以共享内存数据,看起来就像同一个应用的两个部分。

    多进程注意点

    通过指定android:process就可以开启多进程了,但是多进程还是有许多注意的地方的。不仅仅只是指定一个android:process就代表万事大吉了。

    首先我们需要知道,Android应用的一个简单的启动过程。

    1. 桌面(Launcher进程)→AMS(SystemServer进程)→Zygote进程→由Zygote fork自身创建应用程序进程
    2. 创建应用程序进程,应用程序进程是通过请求Zygote进程来创建新的应用程序进程。Zygote进程通过fock自身创建应用程序进程,这样应用程序进程就会获得Zygote进程在启动时创建的Java虚拟机实例,同时在应该程序进程创建过程中还启动了Binder线程池以及消息循环。
    3. 应用程序进程创建出来之后,由AMS去请求应用程序进程去创建启动Activity

    在这里插入图片描述

    回到我们的本片文章的主题,多进程的注意点,我们需要注意的是,在创建进程的时候同时创建了Java虚拟机不同的虚拟机在内存分配上有不同的地址空间,导致在不同的虚拟机中访问同一个类的对象会产生多份副本

    比如我可以写如下的代码,在两个进程中同时访问使用。

    object DataManager{
    	var id = 1
    }
    
    • 1
    • 2
    • 3

    我们在MainActivity中将其改变设置为2,之后再ClientActivity1中打印出该值。

    我们期望再ClientActivity1中打印的值为2,但其实打印出来的是1

    这就是因为在这两个进程管理的内存地址不同,由两个虚拟机进行处理。简单理解就是DataManager再这两个进程中都存在,且这两个类互不干扰,同理这两个进程都存在自己的DataManager单例实例。所以修改当前进程的对象属性并不会影响到另一个进程。

    多进程直接通过内存来共享数据,无一例外都会失败,这也是开启多进程带来的主要影响。

    总的来说来说多进程主要会遇到以下几个问题。

    1. 静态成员和单例模式失效
    2. 线程同步机制失效
    3. SharedPreferences会存在丢数据的可能
    4. Application在每次创建一个新的进程时都会重新走一次

    第一点上面有讲过;第二点和第一点类似,线程同步只保证当前进程多线程同步,另一个进程的无法保证;第三点因为在内存中会有一份SharedPreferences文件的缓存,在多进程模式下,它的读/写就变得不可靠,当面对高并发的读/写访问,Sharedpreferences有很大几率会丢失数据;第四点在进程启动之后启动Activity的过程中会首先启动Application,所以启动多少个进程就会启动多少个虚拟机然后执行多少次Application。所以如果你存在多进程但是部分在Application中的逻辑只想执行此一次,可以判断进程名字,然后再想要的进程中执行。

    android:multiprocess是干什么的?

    AndroidManifest.xml清单中还有一个属性即为multiprocess
    从上面我们知道指定了process名字之后就可以开启多进程了,那么multiprocess又是干嘛呢?
    我们思考一个这样的问题,主进程是process1,又启动了一个进程process2,现在存在一个新的Activity,我们希望它运行在调用者的进程中,那么如何操作呢?
    这时候只需要将android:multiprocess = true则该Activity就会运行到调用者的进程中了。如果是process1调用启动该Activity,那么它就会运行在process1中;如果是process2调用启动该Activity,那么它就会运行在process2中。
    默认情况下android:multiprocess = false,此时不论那个进程调用打开该Activity,如果该Activity指定了process属性,那么它运行在指定的进程中,否则运行到主进程中。

    几种跨进程通信的方法

    实现跨进程通信的方式很多。

    1. 通过Intent来传递数据。
    2. 共享文件。
    3. 基于BinderMessenger
    4. 基于BinderAIDL
    5. Socket

    平时常用的的通过Intent传递数据的方式其实就是一种跨进程的方案,需要序列化。另外还可以使用共享文件Socket等等。当然Android中比较常用的还是Binder了,后面会就Binder进行详细的解析。
    关于文件共享可以参考之前写的一篇测试文章:Android多个进程同时写同一个文件,会怎么样?

    创作不易,如有帮助一键三连咯🙆‍♀️。欢迎技术探讨噢!

  • 相关阅读:
    百多安医疗冲刺科创板:半年营收1亿 为张海军与郭海宏夫妻店
    【Spring】快速入门Spring Web MVC
    python基础简介
    Tomcat服务(部署、虚拟主机配置、优化)
    2024年新版宝塔面板如何安装WordPress网站教程
    SAT Encoding and CDCL Algorithm听课笔记
    序列和【牛客网】
    动手学深度学习——循环神经网络的简洁实现(代码详解)
    【教程】遥感数据与作物模型同化实践
    Mybatis一级二级缓存
  • 原文地址:https://blog.csdn.net/weixin_44235109/article/details/125475115