精华内容
下载资源
问答
  • 2017-05-27 15:49:44

    为何使用多进程

    什么情况下,我们会去想到使用多进程呢?
    就我个人开发实践中就多次使用了Android多进程机制,如项目中的推送业务开发,提出要求如下:

    • 不能影响主业务的代码稳定运行
    • 不能占用主业务的进程内存
    • 不受主业务进程生命周期影响,独立存在和运行
      要满足这3个需求下,不由就会想到在应用内开辟一个新进程单独给推送业务使用,因为其特点明显:
    • 独立进程运行出现了崩溃和异常而退出并不会影响其他进程运行
    • 独立进程意味着有系统开辟的独立内存空间,不会和其他进程产生占用内存,影响其内存分配问题
    • 独立进程的启动和退出可以完全不依赖用户对应用的使用,可以独立启动、退出,也可以不会因应用退出而结束了进程。

    可以看出明显满足上述要求,那如何开辟呢。Android系统中使用多进程配置还是挺简单的,只要在Manifest中组件(如Service、Activity)直接配置android:process=“”属性即可完成配置。 Android下的多进程使用虽然很简单,但是如果不注意细节就很容易出现一些细节上的问题。

    开发细节

    android:process=":XXX"与android:process="XXX"区别

    android:process=":xxx"与android:process=“XXX"不仅仅是用来定义当前进程的名字,一般情况各组件的进程名均为当前应用的包名。那有”:"开头意味着:

    更多相关内容
  • Android 多进程开发

    千次阅读 2017-12-07 18:47:31
    前言  正常情况下,一个apk...但是如果需要将某些组件(如Service、Activity等)运行在单独的进程中,就需要用到android:process属性了。我们可以为android的基础组件指定process属性来指定它们运行在指定进程中。

    前言


           正常情况下,一个apk启动后只会运行在一个进程中,其进程名为AndroidManifest.xml文件中指定的应用包名,所有的基本组件都会在这个进程中运行。但是如果需要将某些组件(如Service、Activity等)运行在单独的进程中,就需要用到android:process属性了。我们可以为android的基础组件指定process属性来指定它们运行在指定进程中。android使用多进程重构项目架构,可以分担主进程压力以免因资源消耗过大被crash掉,另外多进程相互监听唤醒,可以使应用程序长期驻守后台接受即时消息和通知,防止应用被系统回收。下面就总结一下多进程开发的经验及优化。


    一、多进程概念


           一般情况下,一个应用程序就是一个进程,这个进程名称就是应用程序包名。我们知道进程是系统分配资源和调度的基本单位,所以每个进程都有自己独立的资源和内存空间,别的进程是不能任意访问其他进程的内存和资源的。


    二、多进程机制


           四大组件在AndroidManifest文件中注册的时候,有个属性android:process这里可以指定组件的所处的进程。

           对process属性的设置有两种形式:

           第一种形式:android:process=":remote",以冒号开头,冒号后面的字符串原则上是可以随意指定的。如果我们的包名为“com.example.processtest”,则实际的进程名为“com.example.processtest:remote”。这种设置形式表示该进程为当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中。

           第二种形式:android:process="com.example.processtest.remote",以小写字母开头,表示运行在一个以这个名字命名的全局进程中,其他应用通过设置相同的ShareUID可以和它跑在同一个进程。

           下面通过一个例子来进行一下验证。我们定义两个类:ProcessTestActivity和ProcessTestService,然后在AndroidManifest.xml文件中增加这两个类,并为我们的Service指定一个process属性,代码如下:

    <?xml version="1.0" encoding="utf-8"?>  
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
        package="com.example.processtest"  
        android:versionCode="1"  
        android:versionName="1.0" >  
      
        <uses-sdk  
            android:minSdkVersion="8"  
            android:targetSdkVersion="19" />  
      
        <application  
            android:name="com.example.processtest.MyApplication"  
            android:icon="@drawable/ic_launcher"  
            android:label="@string/app_name">  
            <activity  
                android:name=".ProcessTestActivity"  
                android:label="@string/app_name" >  
                <intent-filter>  
                    <action android:name="android.intent.action.MAIN" />  
      
                    <category android:name="android.intent.category.LAUNCHER" />  
                </intent-filter>  
            </activity>  
              
            <service  
                android:name=".ProcessTestService"  
                android:process=":remote">  
            </service>  
        </application>  
      
    </manifest>

    运行代码,通过DDMS进行观察


           我们可以看到两个进程,名字分别是“com.example.processtest”和“com.example.processtest:remote”,进程ID分别为2722和2739。

           ProcessTestService运行在一个单独的私有进程中,如果想让ProcessTestService运行在一个全局进程中,那么只需修改android:process="com.example.processtest.remote"即可。Android为每一个应用程序分配了一个独立的虚拟机,或者说为每个进程都分配了一个独立的虚拟机,不同的虚拟机在内存分配上 有不同的地址空间,这就会导致在不同的虚拟机中访问同一类的对象会产生多份副本。在一个进程中修改某个值只会影响当前进程,对其他进程不会造成任何影响。


    三、多进程优点


    一般来说,Android应用多进程有三个好处:

           1)我们知道Android系统对每个应用进程的内存占用是有限制的,而且占用内存越大的进程,通常被系统杀死的可能性越大。让一个组件运行在单独的进程中,可以减少主进程所占用的内存,降低被系统杀死的概率.

           2)如果子进程因为某种原因崩溃了,不会直接导致主程序的崩溃,可以降低我们程序的崩溃率。

           3)即使主进程退出了,我们的子进程仍然可以继续工作,假设子进程是推送服务,在主进程退出的情况下,仍然能够保证用户可以收到推送消息。


    四、多进程缺点


           我们已经开启了应用内多进程,那么,开启多进程是不是只是我们看到的这么简单呢?其实这里面会有一些陷阱,稍微不注意就会陷入其中。我们首先要明确的一点是进程间的内存空间时不可见的。

    从而,开启多进程后,我们需要面临这样几个问题:

           1)Application的多次重建。运行在同一个进程中的组件是属于同一个虚拟机和同一个Application的,运行在不同进程中的组件是属于两个不同的虚拟机和Application的。

           2)静态成员和单例模式完全失效。

           3)文件共享问题。比如SharedPreferences 的可靠性下降。

           4)断点调试问题。


    1、Application的多次重建

    我们先通过一个简单的例子来看一下第一种情况。

           Manifest文件如上面提到的,定义了两个类:ProcessTestActivity和ProcessTestService,我们只是在Activity的onCreate方法中直接启动了该Service,同时,我们自定义了自己的Application类。代码如下:

    public class MyApplication extends Application {  
        public static final String TAG = "viclee";  
        @Override  
        public void onCreate() {  
            super.onCreate();  
            int pid = android.os.Process.myPid();  
            Log.d(TAG, "MyApplication onCreate");  
            Log.d(TAG, "MyApplication pid is " + pid);  
        }  
    }  
    public class ProcessTestActivity extends Activity {  
        public final static String TAG = "viclee";  
      
        @Override  
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.activity_process_test);  
      
            Log.i(TAG, "ProcessTestActivity onCreate");  
            this.startService(new Intent(this, ProcessTestService.class));  
        }  
    }  
    public class ProcessTestService extends Service {  
        public static final String TAG = "viclee";  
      
        @Override  
        public void onCreate() {  
            Log.i(TAG, "ProcessTestService onCreate");  
        }  
      
        @Override  
        public IBinder onBind(Intent arg0) {  
            return null;  
        }  
      
    }  
    执行上面这段代码,查看打印信息:


           我们发现MyApplication的onCreate方法调用了两次,分别是在启动ProcessTestActivity和ProcessTestService的时候,而且我们发现打印出来的pid也不相同。由于通常会在Application的onCreate方法中做一些全局的初始化操作,它被初始化多次是完全没有必要的。出现这种情况,是由于即使是通过指定process属性启动新进程的情况下,系统也会新建一个独立的虚拟机,自然需要重新初始化一遍Application。那么怎么来解决这个问题呢?

           我们可以通过在自定义的Application中通过进程名来区分当前是哪个进程,然后单独进行相应的逻辑处理。

    public class MyApplication extends Application {  
        public static final String TAG = "viclee";  
      
        @Override  
        public void onCreate() {  
            super.onCreate();  
            int pid = android.os.Process.myPid();  
            Log.d(TAG, "MyApplication onCreate");  
            Log.d(TAG, "MyApplication pid is " + pid);  
      
            ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);  
            List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();  
            if (runningApps != null && !runningApps.isEmpty()) {  
                for (ActivityManager.RunningAppProcessInfo procInfo : runningApps) {  
                    if (procInfo.pid == pid) {  
                         if (procInfo.processName.equals("com.example.processtest")) {  
                             Log.d(TAG, "process name is " + procInfo.processName);  
                         } else if (procInfo.processName.equals("com.example.processtest:remote")) {  
                             Log.d(TAG, "process name is " + procInfo.processName);  
                         }  
                    }  
                }  
            }  
        }  
    } 

    运行之后,查看Log信息:


           图中可以看出,不同的进程执行了不同的代码逻辑,可以通过这种方式来区分不同的进程需要完成的初始化工作。


    2、静态变量和单例模式完全失效

           下面我们来看第二个问题,将之前定义的Activity和Service的代码进行简单的修改,代码如下:

    public class ProcessTestActivity extends Activity {  
        public final static String TAG = "viclee";  
        public static boolean processFlag = false;  
      
        @Override  
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.activity_process_test);  
      
            processFlag = true;  
            Log.i(TAG, "ProcessTestActivity onCreate");  
            this.startService(new Intent(this, ProcessTestService.class));  
        }  
    }  
    public class ProcessTestService extends Service {  
        public static final String TAG = "viclee";  
      
        @Override  
        public void onCreate() {  
            Log.i(TAG, "ProcessTestService onCreate");  
            Log.i(TAG, "ProcessTestActivity.processFlag is " + ProcessTestActivity.processFlag);  
        }  
      
        @Override  
        public IBinder onBind(Intent arg0) {  
            return null;  
        }  
      
    }
    重新执行代码,打印Log:


            从上面的代码和执行结果看,我们在Activity中定义了一个标志processFlag并在onCreate中修改了它的值为true,然后启动Service,但是在Service中读到这个值却为false。按照正常的逻辑,静态变量是可以在应用的所有地方共享的,但是设置了process属性后,产生了两个隔离的内存空间,一个内存空间里值的修改并不会影响到另外一个内存空间。

           针对静态变量失效的问题,我们可以使用Intent或者aidl等进程通讯方式传递内容。


    3、文件共享问题
           第三个问题是文件共享问题。多进程情况下会出现两个进程在同一时刻访问同一个数据库文件的情况。这就可能造成资源的竞争访问,导致诸如数据库损坏、数据丢失等。在多线程的情况下我们有锁机制控制资源的共享,但是在多进程中比较难,虽然有文件锁、排队等机制,但是在Android里很难实现。解决办法就是多进程的时候不并发访问同一个文件,比如子进程涉及到操作数据库,就可以考虑调用主进程进行数据库的操作。


    4、断点调试问题

           最后是断点调试的问题。调试就是跟踪程序运行过程中的堆栈信息,由于每个进程都有自己独立的内存空间和各自的堆栈,无法实现在不同的进程间调试。不过可以通过下面的方式实现:调试时去掉AndroidManifest.xml中android:process标签,这样保证调试状态下是在同一进程中,堆栈信息是连贯的。待调试完成后,再将标签复原。


    五、多进程使用场景


           类似音乐类、跑步健身类、手机管家类等长时间需要在后台运行的应用。这些应用的特点就是,当用户切到别的应用,或者关掉手机屏幕的时候,应用本身的核心模块还在正常运行,提供服务。如果因为手机内存过低,或者是进程重要性降低,导致应用被杀掉,后台服务停止,对于这些应用来说,就是灭顶之灾。合理利用多进程,将核心后台服务模块和其他UI模块进行分离,保证应用能更稳定的提供服务,从而提升用户体验。


    举个例子:

    现在要做一款音乐播放器,现在有以下几种方案:
    A. 在Activity中直接播放音乐。
    B. 启动后台Service,播放音乐。
    C. 启动前台Service,播放音乐。
    D. 在新的进程中,启动后台Service,播放音乐。
    E. 在新的进程中,启动前台Service,播放音乐。


    A. 在Activity中直接播放音乐。
           在A中,我们的播放器是直接在activity中启动的。首先这么做肯定是不对的,我们需要在后台播放音乐,所以当activity退出后就播不了了,之所以给出这个例子是为了控制变量作对比。
           然后我们来看下A的使用场景。
           音乐播放器无非是打开app,选歌,播放,退到桌面,切其他应用。我们选取了三个场景,打开、按home切换其他应用、按back退回桌面。让我们看一下A的相对应的oom_adj、oom_score、oom_score_adj的值。(下面三张图依次对应为【打开状态】、【按了Home键被切换状态】、【按了Back键被退出状态】)

    上图为打开状态下oom_adj、oom_score、oom_score_adj的值

    上图为按了Home键状态下oom_adj、oom_score、oom_score_adj的值

    上图为按了Back键状态下oom_adj、oom_score、oom_score_adj的值

           当我们应用在前台的时候,无论adj还是score还是score_adj,他们的值都非常的小,基本不会被LMK所杀掉,但是当我们按了Home之后,进程的adj就会急剧增大,变为7,相应的score和score_adj也会增大。在上篇文章中我们得知,adj=7即为被切换的进程,两个进程来回切换,上一个进程就会被设为7。当我们按Back键的时候,adj就会被设为9,也就是缓存进程,优先级比较低,有很大的几率被杀掉。


    B. 启动后台Service,播放音乐。
           B是直接启动一个后台service并且播放音乐,这个处理看起来比A好了很多,那么实际上,B的各个场景的优先级和A又有什么不同呢?让我们来看下B的对应的打开、切换、退出相应的adj、score、score_adj的值。(下面三张图依次对应为【打开状态】、【按了Home键被切换状态】、【按了Back键被退出状态】)

    上图为打开状态下oom_adj、oom_score、oom_score_adj的值

    上图为按了Home键状态下oom_adj、oom_score、oom_score_adj的值

    上图为按了Back键状态下oom_adj、oom_score、oom_score_adj的值

           B的情况其实是与A类似的,三种状态的adj、score_adj的值都是一样的,只有score有一点出入,其实分析源码得知,LMK杀进程的时候,score的左右其实并不大,所以我们暂时忽略它。所以,与A相比,他们的adj和score_adj的值都相同,如果遇到内存不足的情况下,这两个应用谁占得内存更大,谁就会被杀掉。不过鉴于A实在activity中播放音乐,所以B还是比A略好的方案。


    C. 启动前台Service,播放音乐。
           C的话是启动一个前台Service来播放音乐。让我们来看一下对应的值。(下面三张图依次对应为【打开状态】、【按了Home键被切换状态】、【按了Back键被退出状态】)

    上图为打开状态下oom_adj、oom_score、oom_score_adj的值

    上图为按了Home键状态下oom_adj、oom_score、oom_score_adj的值

    上图为按了Back键状态下oom_adj、oom_score、oom_score_adj的值

           在前台的时候,和AB是一样的,adj都是0,当切到后台,或者back结束时,C对应的adj就是2,也就是可感知进程。adj=2可以说是很高优先级了,非root手机,非系统应用已经没有办法将其杀掉了。adj<5的应用不会被杀掉。
           总的来说,C方案比B优秀,拥有前台Service的C更不容易被系统或者其他应用所杀掉了,进程的优先级一下子提高到了2,相对于B来说更稳定,用户体验更好。不过有一点不足是必须启动一个前台service。不过现在大部分的音乐类软件都会提供一个前台service,也就不是什么缺点了。其实也是有灰色方法可以启动一个不显示通知的前台service,这里就不过多介绍了。

    那么还有可改进的余地吗?
    答案当然是肯定的。


    D. 在新的进程中,启动后台Service,播放音乐。
           终于我们的主角,多进程登场了。
           D把应用进行了拆分,把用于播放音乐的service放到了新的进程内,让我们看一下对应的值。(下面三张图依次对应为【打开状态】、【按了Home键被切换状态】、【按了Back键被退出状态】)

    上图为打开状态下oom_adj、oom_score、oom_score_adj的值

    上图为按了Home键状态下oom_adj、oom_score、oom_score_adj的值

    上图为按了Back键状态下oom_adj、oom_score、oom_score_adj的值

           上面三张图对应的是D应用主进程的ADJ相关值,我们可以看出来,跟A类似,adj都是0,7,9。由于少了service部分,内存使用变少,最后计算出的oom_score_adj也更低了,意味着主进程部分也更不容易被杀死。

    下面我们看下拆分出的service的相关值

    上图为后台Service的oom_adj、oom_score、oom_score_adj的值

           因为是service进程,所以不受打开,关闭,切换所影响,这里就放了一张图。
           我们可以看到,service的adj值一直是5,也就是活跃的服务进程,相比于B来说,优先级高了不少。不过对于C来说,其实这个方案反倒不如C的adj=2的前台进程更稳定。但是D可以自主释放主进程,使D实际所占用的内存很小,从而不容易被杀掉。那么到底C和D谁是更优秀的设计?我个人认为,在ABCDE这5个设计中,D是最具智慧的设计,具体是为什么?先卖个关子,等我们说完了E,再作总结。


    E. 在新的进程中,启动前台Service,播放音乐。

           E也是使用了多进程,并且在新进程中,使用了前台service,先来看下对应的值。(下面三张图依次对应为【打开状态】、【按了Home键被切换状态】、【按了Back键被退出状态】)

    上图为打开状态下oom_adj、oom_score、oom_score_adj的值

    上图为按了Home键状态下oom_adj、oom_score、oom_score_adj的值

    上图为按了Back键状态下oom_adj、oom_score、oom_score_adj的值

           这个不多解释,和ABD基本差不多,都是0,7,9。我们看下拆分出来的进程的值。

    上图为后台Service的oom_adj、oom_score、oom_score_adj的值
           我们可以看到,这个进程的值是2,像C方案,非常小,非常稳定,而且,我们还可以在系统进入后台后,手动杀掉主进程,使整个应用的内存消耗降到最低,内存低,优先级又高,E获得了今天的最稳定的方案奖。


    小结
           ABCDE,5种方案都已经分析完了。显然,E是最稳定的方案,不过,我刚才说过,我个人最倾向于D方案,并且认为D是最智慧的方案,这是为什么呢?
           其实我们可以做个比喻,把整个Android系统比喻成一个旅游景点,Low Memory Killer就是景点的门卫兼保安,然后我们每个进程的ADJ相当于手里的门票,有的人是VIP门票,有的人是普通门票。景点平常没人的时候还好,谁拿票都能进,当人逐渐拥挤的时候,保安就开始根据票的等级,往外轰人。E方案就是一个拿着普通票的妈妈,带着一个VIP的孩子去参观,D方案就是一个拿着普通票的妈妈,带着一个拿着中等票的孩子参观。当内存不够的时候,保安会先把两个妈妈轰出去,孩子们在里面看,再不够了,就会把D孩子给轰出去。这么看来,显然E的效果更好一些,不过由于Android系统对于VIP票的发放没有节制,大家都可以领VIP票,那也就是相当于没有VIP票了。所以如果E方案是一种精明,那么D才是真正的智慧。将调度权还给系统,做好自己,维护好整个Android生态。

    多模块应用



           多进程还有一种非常有用的场景,就是多模块应用。比如我做的应用大而全,里面肯定会有很多模块,假如有地图模块、大图浏览、自定义WebView等等(这些都是吃内存大户),还会有一些诸如下载服务,监控服务等等,一个成熟的应用一定是多模块化的。

           首先多进程开发能为应用解决了OOM问题,Android对内存的限制是针对于进程的,这个阈值可以是48M、24M、16M等,视机型而定,所以,当我们需要加载大图之类的操作,可以在新的进程中去执行,避免主进程OOM。

           多进程不光解决OOM问题,还能更有效、合理的利用内存。我们可以在适当的时候生成新的进程,在不需要的时候及时杀掉,合理分配,提升用户体验。减少系统被杀掉的风险。

           多进程还能带来一个好处就是,单一进程崩溃并不影响整体应用的使用。例如我在图片浏览进程打开了一个过大的图片,java heap 申请内存失败,但是不影响我主进程的使用,而且,还能通过监控进程,将这个错误上报给系统,告知他在什么机型、环境下、产生了什么样的Bug,提升用户体验。

           再一个好处就是,当我们的应用开发越来越大,模块越来越多,团队规模也越来越大,协作开发也是个很麻烦的事情。项目解耦,模块化,是这阶段的目标。通过模块解耦,开辟新的进程,独立的JVM,来达到数据解耦目的。模块之间互不干预,团队并行开发,责任分工也明确。至于模块化开发与多进程的结合,后续会写一篇专门的文章来研究这个问题。



    展开全文
  • 主要为大家简单分析Android开发多进程共享数据,怎么做才能让这两边共享数据,感兴趣的小伙伴们可以参考一下
  • Android多进程的实现

    千次阅读 2019-05-20 11:39:01
    一般,一个app只有一个进程,但会有个线程,比如UI主线程,各种网络请求的子线程。 但是,一些大型的app,比如QQ,会有进程!刚通过top命令,看了一下QQ运行时的进程: 10644 u0_a130 20 0 12% S 57 1425816K ...

    前言

    一般,一个app只有一个进程,但会有多个线程,比如UI主线程,各种网络请求的子线程。
    但是,一些大型的app,比如QQ,会有多个进程!刚通过top命令,看了一下QQ运行时的进程:

    10644 u0_a130  20   0  12% S    57 1425816K  86924K  bg com.tencent.mobileqq:tool
    10371 u0_a130  16  -4   5% S   107 1765092K 176420K  bg com.tencent.mobileqq:mini
     3195 u0_a130  20   0   1% S    49 1401268K  53152K  fg com.tencent.mobileqq:MSF
     3271 u0_a130  10 -10   0% S   130 1744152K 161772K  ta com.tencent.mobileqq
    10451 u0_a130  20   0   0% S    38 1382680K  66268K  bg com.tencent.mobileqq:mini3
    29008 u0_a130  20   0   0% S    31 1367512K  38376K  fg com.tencent.mobileqq:TMAssistantDownloadSDKService
    

    艾玛,太过分了,竟然有6个进程!我们知道,在Android中,系统会为每个应用或进程分配独立的虚拟机和内存空间,看来,QQ内存欲很强呀,通过增加进程这种方式,满足内存需要呀^^

    使用多进程的场景

    一般有2种情况,需要使用多进程。

    1. 内存不够,扩大内存。
    2. 一些业务,希望在单独进程运行。
      比如,QQ的一些插件功能(微视),希望在一个独立进程运行,当它遇到崩溃时,不会影响QQ退出(毕竟进程不同)

    开启多进程

    很简单,在AndroidManifest.xml中注册Service、Activity、Receiver、ContentProvider时指定android:process属性。

    <service
        android:name=".RemoteService"
        android:process=":remote">
    </service>
    
    <activity
        android:name=".RemoteActivity"
        android:process="com.chenxf.ipc.remote">
    </activity>
    

    有两种声明方式,一个加冒号,一个完整的名字,区别如下:
    :remote: 以冒号开头是一种简写,系统会在当前进程名前附件当前包名,完整的进程名为:com.chenxf.ipc:remote,同时以冒号开头的进程属于当前应用的私有进程,其它应用的组件不能和它跑在同一进程。

    com.chenxf.ipc.remote:这是完整的命名方式,不会附加包名,其它应用如果和该进程的ShareUID、签名相同,则可以和它跑在同一个进程,实现数据共享。(一般极少这样用,除非是同一公司开发的app,且2个app关联很大,才会签名也一样)

    多进程的优缺点

    优点

    其实就是上面的场景,算是它的优点。

    1. 增加内存。
    2. 业务隔离。一些子业务,放子进程,如果崩溃了,不会影响主app退出。

    缺点

    1. 静态成员和单例模式失效
    2. 线程同步机制失效
    3. SharedPreferences 可靠性降低
    4. Application 被多次创建

    1, 2 很容易理解,每个应用或进程分配独立的虚拟机,不同的虚拟机自然占有不同的内存地址空间。可以认为,每个进程,都有独立的静态成员和单例模式的对象,所以进程之间,千万不能通过这些通信,因为它们属于不同的时空喔。
    3嘛,如果一个读,一个写,还好,要是同时去写,就可能出问题了,A进程刚写1,B进程又写2,A一脸懵逼,为啥变成2了,你说可靠不可靠。
    4很重要,指的是,Application会被重复创建。比如,如果有3个进程,Application会初始化3次。如果希望不同进程做不同的初始化,则可以参考如下的实现:

    package com.chenxf.processtest;
    
    import android.app.ActivityManager;
    import android.app.Application;
    import android.content.Context;
    import android.text.TextUtils;
    import android.util.Log;
    
    public class MyApplication extends Application {
        private static final String TAG = "MyApplication";
        private static final String DOWNLOADER_PROCESS = ":downloader";
        private static final String PLUGIN_PROCESS = ":plugin";
    
        private BaseApplication mProxy;
    
        @Override
        public void onCreate() {
            super.onCreate();
            String processName = getMyProcessName();
            Log.i(TAG, "onCreate " + processName);
            initProxyApplication(processName);
        }
    
        private void initProxyApplication(String processName) {
            String mPackageName = getPackageName();
    
            if (TextUtils.equals(mPackageName, processName)) {
                //主进程
                Log.i(TAG, "init process " + mPackageName);
                mProxy = new MainApplication(processName);
            } else if (TextUtils.equals(processName, mPackageName + PLUGIN_PROCESS)) {
                //插件安装进程
                Log.i(TAG, "init process " + PLUGIN_PROCESS);
                mProxy = new PluginApplication(processName);
            } else if (TextUtils.equals(processName, mPackageName + DOWNLOADER_PROCESS)) {
                //下载进程
                Log.i(TAG, "init process " + DOWNLOADER_PROCESS);
                mProxy = new DownloaderApplication(processName);
            } else {
                mProxy = new BaseApplication(processName);
            }
        }
    
        /**
         * 获取进程的名称
         *
         * @return
         */
        public String getMyProcessName() {
            if (mProxy != null) {
                return mProxy.getProcessName();
            } else {
                return initCurrentProcessName(this);
            }
        }
    
        private String initCurrentProcessName(Context context) {
            int pid = android.os.Process.myPid();
            ActivityManager manager =
                    (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
            for (ActivityManager.RunningAppProcessInfo process : manager.getRunningAppProcesses()) {
                if (process.pid == pid) {
                    return process.processName;
                }
            }
            return null;
        }
    }
    

    多进程的通信

    有多种通信方式,包括:
    AIDL:功能强大,支持进程间一对多的实时并发通信,并可实现 RPC (远程过程调用)。
    Messenger:支持一对多的串行实时通信, AIDL 的简化版本,不需要写AIDL文件,只能支持一次处理一个调用。
    ContentProvider:强大的数据源访问支持,主要支持 CRUD 操作,一对多的进程间数据共享,例如我们的应用访问系统的通讯录数据。
    BroadcastReceiver:即广播,但只能单向通信,接收者只能被动的接收消息。
    文件共享:在非高并发情况下共享简单的数据。
    Socket:通过网络传输数据。

    AIDL最为复杂,网上也有很多文章介绍,这里根据多进程的情况下,来写一个AIDL实现多进程通信吧。

    AIDL实现多进程通信

    服务端实现

    服务端,咱单独建一个模块,如downloader。模块的Manifest声明一个service在独立进程。
    service加一个action,方便其他模块启动service。

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.chenxf.downloader">
    
        <application>
            <service
                android:name=".DownloadService"
                android:enabled="true"
                android:exported="true"
                android:process=":downloader">
                <intent-filter>
                    <action android:name="com.chenxf.downloader.action.START_SERVICE" />
                </intent-filter>
            </service>
        </application>
    
    </manifest>
    

    选中模块,右键,New -> AIDL -> AIDL File。
    创建一个文件,IDownloadAidl。

    // IDownloadAidl.aidl
    package com.chenxf.downloader;
    import com.chenxf.downloader.DownloadBean;
    // Declare any non-default types here with import statements
    
    interface IDownloadAidl {
        void sendMessage(in DownloadBean url);//注意加in,不然编不过
        DownloadBean getMessage(in DownloadBean param);
    }
    

    以上代码的DownloadBean是传输数据用的,需要也写一个AIDL文件才能编译过:

    // DownloadBean.aidl
    package com.chenxf.downloader;
    
    // Declare any non-default types here with import statements
    
    parcelable DownloadBean;
    

    这个文件,注意写法和上面不一样,不是interface,是parcelable,待会我们还得实现一个包名一致的类,DownloadBean,继承Parcelable。

    接着,执行Build-> Make Project,编译downloader模块,将会生成一个文件。
    在这里插入图片描述
    这个文件声明了一些类,看起来乱七八糟,其实跟我们有关系的,只有一个内部类:IDownloadAidl.Stub。服务端,需要继承IDownloadAidl.Stub,来实现对应的函数。

    package com.chenxf.downloader;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteException;
    
    public class DownloadService extends Service {
        private DownloadServiceStub downloadServiceStub;
        public DownloadService() {
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            downloadServiceStub = new DownloadServiceStub();
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
            return downloadServiceStub;
        }
    
        public class DownloadServiceStub extends IDownloadAidl.Stub {
    
    
            @Override
            public void sendMessage(DownloadBean url) throws RemoteException {
    
            }
    
            @Override
            public DownloadBean getMessage(DownloadBean param) throws RemoteException {
                DownloadBean result = new DownloadBean();
                result.setDownloadResult("/sdcard/xx.mp4");
                return result;
            }
        }
    }
    
    

    很简单吧,对了,DownloadBean 还要实现一下:

    package com.chenxf.downloader;
    
    import android.os.Parcel;
    import android.os.Parcelable;
    
    public class DownloadBean implements Parcelable {
        String url;
    
        String downloadResult;
    
        public DownloadBean() {
        }
    
        public DownloadBean(String url) {
            this.url = url;
        }
    
    
        public String getUrl() {
            return url;
        }
    
        public void setUrl(String url) {
            this.url = url;
        }
    
        public String getDownloadResult() {
            return downloadResult;
        }
    
        public void setDownloadResult(String downloadResult) {
            this.downloadResult = downloadResult;
        }
    
    
        protected DownloadBean(Parcel in) {
            url = in.readString();
            downloadResult = in.readString();
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(url);
            dest.writeString(downloadResult);
        }
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        public static final Creator<DownloadBean> CREATOR = new Creator<DownloadBean>() {
            @Override
            public DownloadBean createFromParcel(Parcel in) {
                return new DownloadBean(in);
            }
    
            @Override
            public DownloadBean[] newArray(int size) {
                return new DownloadBean[size];
            }
        };
    }
    
    

    好了,服务端写好啦。

    接着是客户端调用。也很简单。

    客户端实现

    客户端就写在app模块吧,gradle得依赖downloader模块,这样,DownloadBean才可以用。我们让一个activity绑定远程Service,然后通信。
    ps:记得activity退出时,unbindService。

    package com.chenxf.processtest;
    
    import android.app.Service;
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Toast;
    
    import com.chenxf.downloader.DownloadBean;
    import com.chenxf.downloader.DownloadService;
    import com.chenxf.downloader.IDownloadAidl;
    
    public class MainActivity extends AppCompatActivity {
        private static final String TAG = "MainActivity";
        private IDownloadAidl downloadAidl;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            findViewById(R.id.start_service).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    handleClick();
                }
            });
        }
    
        private void handleClick() {
            if(downloadAidl == null) {
                //点击时,才开启进程,没有start的话,系统不会有downloder进程
                startService();
            } else {
                try {
                    DownloadBean result = downloadAidl.getMessage(new DownloadBean("http://xx.mp4"));
                    Toast.makeText(MainActivity.this, "result " + result.getDownloadResult(), Toast.LENGTH_LONG).show();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            if(downloadAidl != null) {
                unbindService(conn);
            }
        }
    
        private void startService() {
        // 创建所需要绑定的Service的Intent
    //        Intent intent = new Intent();
    //        intent.setAction("com.chenxf.downloader.action.START_SERVICE");
    //        intent.setPackage("com.chenxf.downloader");
    //        // 绑定远程的服务
    //        bindService(intent, conn, Service.BIND_AUTO_CREATE);
            Intent intent = new Intent(this, DownloadService.class);
            bindService(intent, conn, Service.BIND_AUTO_CREATE);
        }
    
        private ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.i(TAG, "onServiceDisconnected " +name);
    
                downloadAidl = null;
            }
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                // 获取远程Service的onBinder方法返回的对象代理
                downloadAidl = IDownloadAidl.Stub.asInterface(service);
                Log.i(TAG, "onServiceConnected " +name +" downloadAidl" +downloadAidl );
            }
        };
    
    
    }
    
    

    需要强调的是,虽然我们声明了DownloadService是在独立进程,但只有这个service启动了,进程才会被创建,否则不会喔!

    完整源码

    https://github.com/newchenxf/MultiProcess

    参考文献

    Android 多进程通信

    展开全文
  • 一个可以启动多进程捕获手机崩溃信息的Android开发组件
  • Android开发多进程详解

    千次阅读 2016-06-14 17:34:53
    相信很Android开发的同学对进程Android中这个概念,都不怎么说的清楚,网路上有的说是一个应用程序,这其实是不对的,w为了研究Android进程的概念,我这里写了一个很简单的代码, android:name=...

    相信很多做Android开发的同学对进程在Android中这个概念,都不怎么说的清楚,网路上有的说是一个应用程序,这其实是不对的,w为了研究Android中进程的概念,我这里写了一个很简单的代码,

      <application
            android:name="com.example.nine.MyApplication"
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.Light.NoTitleBar" >
            <activity
                android:name=".MyProcessActivityA"
                android:label="@string/app_name"
                android:process=":text.a" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity
                android:name="com.example.nine.MyProcessActivityB"
                android:process=":text.b" >
            </activity>
        </application>

    这里我在aciticyA和B里分别加入了process标签,意思就是让这两个activity运行在不同的进程里面。

    下面是具体代码:

    package com.example.nine;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import android.app.Activity;
    import android.app.ActivityManager;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.TextView;
    
    public class MyProcessActivityA extends Activity {
        private TextView tv1, tv2, tv3, tv4, tv5, tv6;
        private Button bt;
        private List<String> list;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_a);
            initViews();
            initData();
        }
    
        private void initViews() {
            tv1 = (TextView) findViewById(R.id.tv1);
            tv2 = (TextView) findViewById(R.id.tv2);
            tv3 = (TextView) findViewById(R.id.tv3);
            tv4 = (TextView) findViewById(R.id.tv4);
            tv5 = (TextView) findViewById(R.id.tv5);
            tv6 = (TextView) findViewById(R.id.tv6);
            bt = (Button) findViewById(R.id.bt);
            bt.setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    startActivity(new Intent(MyProcessActivityA.this,MyProcessActivityB.class));
                }
            });
        }
    
        private void initData() {
            list = new ArrayList<String>();
            for (int i = 0; i <1000000; i++) {
                list.add(i+"aaaaaaaaaaaaaaaaaaa");
            }
            Text.i = 1;
            tv1.setText("当前线程id:"+Thread.currentThread().getId());
            tv2.setText("当前进程Pid:"+android.os.Process.myPid());
            tv3.setText("当前进程名称:"+MyUtil.getCurProcessName(this));
            tv4.setText("全局静态变量i:"+Text.i);
            tv5.setText("当前申请的总内存:"+Runtime.getRuntime().totalMemory()/1024/1024+"M");
            tv6.setText("单个进程分配的内存上限:"+Runtime.getRuntime().maxMemory()/1024/1024+"M");
        }
    
    }
    
    package com.example.nine;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import android.app.Activity;
    import android.app.ActivityManager;
    import android.content.Context;
    import android.os.Bundle;
    import android.widget.TextView;
    
    public class MyProcessActivityB extends Activity{
        private TextView tv1, tv2, tv3, tv4, tv5, tv6;
        private List<String> list;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_b);
            initViews();
            initData();
        }
    
        private void initViews() {
            tv1 = (TextView) findViewById(R.id.tv1);
            tv2 = (TextView) findViewById(R.id.tv2);
            tv3 = (TextView) findViewById(R.id.tv3);
            tv4 = (TextView) findViewById(R.id.tv4);
            tv5 = (TextView) findViewById(R.id.tv5);
            tv6 = (TextView) findViewById(R.id.tv6);
        }
    
        private void initData() {
            list = new ArrayList<String>();
            for (int i = 0; i <1000000; i++) {
                list.add(i+"aaaaaaaaaaaaaaaaaaa");
            }
            tv1.setText("当前线程id:"+Thread.currentThread().getId());
            tv2.setText("当前进程Pid:"+android.os.Process.myPid());
            tv3.setText("当前进程名称:"+MyUtil.getCurProcessName(this));
            tv4.setText("全局静态变量i:"+Text.i);
            tv5.setText("当前申请的总内存:"+Runtime.getRuntime().totalMemory()/1024/1024+"M");
            tv6.setText("单个进程分配的内存上限:"+Runtime.getRuntime().maxMemory()/1024/1024+"M");
        }
    
    }
    
    package com.example.nine;
    
    import android.app.ActivityManager;
    import android.content.Context;
    import android.content.Intent;
    import android.util.Log;
    
    public class MyUtil {
    public static String getCurProcessName(Context context) {
          int pid = android.os.Process.myPid();
          ActivityManager mActivityManager = (ActivityManager) context
            .getSystemService(Context.ACTIVITY_SERVICE);
          for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager
            .getRunningAppProcesses()) {
           if (appProcess.pid == pid) {
    
            return appProcess.processName;
           }
          }
          return null;
         }
    }
    
    package com.example.nine;
    
    import android.app.ActivityManager;
    import android.app.Application;
    import android.content.Context;
    import android.util.Log;
    
    public class MyApplication extends Application{
        @Override
        public void onCreate() {
            // TODO Auto-generated method stub
            super.onCreate();
            Log.e("ttext","Application onCreate"+"进程名称"+MyUtil.getCurProcessName(getApplicationContext()));
        }
    }
    

    这里写图片描述

    这里写图片描述

    这里写图片描述

    这里写图片描述

    下面我们足一进行分析:

    1.这两个activity虽然属于不同的进程(text.a和text.b),但是我们看到打印出来的线程ID是一样的,都是主线程的ID,说明四大组件不管属于哪个进程,都一定是运行在主线程中的

    2.大家可以看到,我这个手机,分配给单个进程的内存上限是192M,但是如果是两个进程,142+142>192M,每个进程上限都是192M,互相独立不影响;如果app特别复杂,可以考虑多开进程,提高内存分配上限

    3.关于全局变量,Text.i,这是一个静态变量,我在A里面设置成了1,但是在B里面引用,仍然初始化为0,说明不同进程之间不能共享全局变量

    4.关于application的创建问题,从最后的截图可以看到,每个进程被加载,都会创建一个application对象,所以一个app里面不一定只有一个application对象

    5.关于application再说一点,同一个进程之间的全局变量的保存也最好不要用application对象来保存,因为如果app切换到后台被杀死过后,application是会重建的,这个时候你保存的变量就会初始化。
    同一个进程,当我们退出应用程序过后,application其实并没有立刻被杀死,这时你再点击应用进入,application并不会再次被重建,里面的还会保留以前的全局数据,那么我们要怎么才能保证在退出程序的时候,把数据清空呢?
    在退出的时候,关闭进程即可。

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        System.exit(0);
    }

    值得注意的是,System.exit(0);只能关闭当前进程。

    另外,还有两种方法可以关闭进程,分别是通过包名和PID。

    ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 
    manager.killBackgroundProcesses(package);
    android.os.Process.killProcess(android.os.Process.myPid());

    6.关于多进程之间数据传递的问题,这里我并没有写出demo,但是大体思路就是以下几种:

    a。通过Intent在四大组件中传值。(这一点不管是同一个app里面的多进程还是不同app之间的多进程都可以)

    值得注意的是,intent不能直接传递对象,如果要传递对象则要实现序列化的接口Parcelable或者是Serializable接口,本质上都是转化成字节流传输,这两个接口不同之处在于Parcelable是内存中读写速度较快但是占用内存,Serializable是文件读写速度较慢但是内存占用少。

    b.通过本地存储共享数据.
    数据库或者xml都行。

    c.关于网路上有的人说的什么多进程访问本地文件,会有线程不安全的问题,这个其实并不正确,只要保证是在主线程中操作,就一定是线程安全的(原理参考第1点),当然如果你新建一个线程来读写,那就要用handler来保证线程安全了。

    最后,我试着解释下Android开发里面的进程的概念吧,其实谷歌官方是把Android里面的进程概念给弱化掉了,让我们更加关心主线程,四大组件,不过强行要解释的话,可以认为一个aplication对应一个进程。

    展开全文
  • Android多进程实现及常见问题

    千次阅读 2016-12-28 14:23:07
    Android多进程实现及常见问题   1、为什么需要多个进程? 默认情况下,一个Android应用中所有的组件都会运行在以包名为进程名的单个进程中,但是由于Android自身平台的一些限制或者多进程固有的一些好处,导致很多...
  • 不过,单进程开发并不是Android应用的全部,今天我们就来说说Android中的多进程开发以及多进程的使用场景。 多进程介绍 本篇文章内容基于Android Developer 在Android中,默认情况下,同一应用的所有组件均运行在...
  • Android IPC多进程通信 aidl
  • 不过,单进程开发并不是Android应用的全部,今天我们就来说说Android中的多进程开发以及多进程的使用场景。 1. 进程 我们都知道Android系统是基于Linux改造而来的,进程系统也是一脉相承,进程其实就是程序的...
  • 通过对Android多媒体实战开发技术,如图像、音频、视频、2D和3D的详细讲解,让读者学会如何在应用开发中应用多媒体技术为自己的APP增加炫酷的效果,特别是Android5.0新出现的API这些特性是目前市面上的一些书籍所...
  • 前言 正常情况下,一个apk启动后只会运行在一个进程中,其进程名...但是如果需要将某些组件(如Service,Activity等)运行在单独的进程中,就需要用到android:process属性了。我们可以给android的组件设置android:p...
  • Android 多进程的基础使用及优缺点

    千次阅读 2017-04-08 19:20:58
    前言说起进程,不得不说说进程和线程之前的关系。在操作系统角度描述,线程是CPU调度的最小...我们可以使用多进程分担主进程压力以免因资源消耗过大被crash掉,另外多进程相互监听可以唤醒,使应用程序长期驻守后...
  • Android 多进程调试技巧

    千次阅读 2019-07-16 13:54:07
    之前开发多进程的应用,想要调试Application 里面的代码,一直调试不了代码。 因为是多进程,Application 会执行两次。 原因: 比如我们有两个进程,一个叫进程a, 一个叫进程b. 因为我们android debug 的时候,选择...
  • Android进程间通信总结

    千次阅读 2021-09-06 21:26:37
    ​ IPC为 (Inter-Process Communication) 缩写,称为进程间通信或跨进程通信,指两个进程间进行数据交换的过程。安卓中主要采用 Binder 进行进程间通信,当然也支持其他 IPC 方式,如:管道,Socket,文件共享,...
  • android多进程深入分析

    千次阅读 2017-02-21 18:24:00
    android一个应用程序,可以存在多个进程, 在某些场景,比如希望获得更多的内存、希望功能模块间不相互影响,或者彻底解决webview内存泄漏等, ...看似好用且强大的多进程,也是一把双刃剑,今天就深入分析分析多进程
  • 一、多进程访问同一个数据库是否安全 背景:多个进程代表多个数据库操作instance,每个进程有自己的ApplicationContext。多个进程内存不共享。 写代码做了测试测试代码在最后,虽然sqlite不是线程安全的,但是在...
  • Android 多进程使用场景

    千次阅读 2017-01-12 14:30:30
    本文章原作者已授权转载 原文地址...在上一篇《Android 线程介绍》中,我们大概了解了一下Android中的进程的概念以及其生命周期,另外还有Low Memory Kill...
  • Android平台支持多进程通信,也支持应用内实现多进程Android中,默认一个APK包就对应一个进程,其进程名就为AndroidManifest.xml文件中 指定的package名。我们可以通过Activity,Service,BroadCastReceiver,...
  • 一、WebView面临的问题: 1、WebView导致的内存泄漏问题,...WebView独立进程的实现比较简单,只需要在AndroidManifest中找到对应的WebViewActivity,对其配置"android: process"属性即可。如下: <!--独立进程W
  • Android系统中的进程之间不能共享内存,需要提供一些机制在不同进程之间进行数据通信,这个机制就是AIDL。 1. AIDL: Android Interface definition language Android内部进程通信接口的描述语言,通过它我们可以定义...
  • 最近遇到一个bug,当应用加了多进程后,比如总共进程数为N,会出现在startService()时onStartCommand()方法会被重复调用(N-1)次的奇怪现象。祸起 最近遇到两个模块互不相干却受到影响的奇怪问题,一个push模块...
  • Android底层开发

    千次阅读 2021-12-13 14:10:26
    学习书籍:Android底层开发实践 使用代码:AOSP源码 带@的行表示关键点; 橙色背景的文字表示:整编log分析的关键字 绿色“待补充”文字表示:有待补充内容 -----第三章 Android系统开发环境搭建 3.1 ...
  • 文章目录概述Bootloader 引导装载和启动 Linux 内核启动 Init 进程(基于 Android9 源码)Init 进程的初始化过程main 函数执行流程解析启动 init.rcinit 文件格式介绍init 进程对信号的处理 概述 在介绍 Init 之前...
  • Android多进程概念:一般情况下,一个应用程序就是一个进程,这个进程名称就是应用程序包名。我们知道进程是系统分配资源和调度的基本单位,所以每个进程都有自己独立的 资源和内存空间,别的进程是不能任意访问...
  • Android 多进程注意事项

    千次阅读 2017-01-12 14:31:43
    推荐资源站:https://zhimalier.com/ ... 上篇文章《Android多进程使用场景》中,我们分析了一下多进程的使用场景,今天这篇文章,我们来聊聊Android多进程开发过程中可能会遇到的问题。 多虚拟...
  • Android进程通信Binder机制与AIDL实例

    千次阅读 2021-12-03 23:10:34
    文章目录进程通信1.1 进程空间划分1.2 跨进程通信IPC1.3 Linux跨进程通信1.4 Android进程通信Binder 跨进程通信2.1 Binder简介2.2 Binder驱动2.3 Binder原理AIDL编程Demo3.1 服务端3.2 客户端 在操作系统中,进程与...
  • 接下来通过一个实例来看看怎么具体地借助 ContentProvider 和 Binder 来进行便捷的跨进程通信。 Server进程 服务端接口定义 在服务端进程或者服务端 App 中,定义 AIDL 接口文件: interface IMyAidlInterface { int...
  • Android SDK 提供了在 Android 平台上使用 JaVa 语言进行 Android 应用开发必须的工具和 API 接口。 特性 • 应用程序框架 支持组件的重用与替换 • Dalvik Dalvik Dalvik Dalvik 虚拟机 专为移动设备优化 • ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 107,919
精华内容 43,167
热门标签
关键字:

android多进程开发