e-works数字化企业网  »  文章频道  »  基础信息化  »  移动应用

巧用Android多进程,微信,微博等主流App都在用

2017/6/24    来源:微信    作者:佚名      
关键字:Android  微信  
笔者认为合理使用多进程不仅仅是有多大好处的问题,而且是很有必要的;所以说,最好还是根据自身情况,考虑一下是否需要拆分进程。
    1.前言
 
    对于进程的概念,来到这里的都是编程修仙之人,就不再啰嗦了,相信大家倒着、跳着、躺着、各种姿势都能背出来。
 
    2.为什么要使用多进程?
 
    相信很多同学在实际开发中,基本都不会去给app划分进程,而且,在Android中使用多进程,还可能需要编写额外的进程通讯代码,还可能带来额外的Bug,这无疑加大了开发的工作量,在很多创业公司中工期也不允许,这导致了整个app都在一个进程中。
 
    整个app都在一个进程有什么弊端?
 
    在Android中,虚拟机分配给各个进程的运行内存是有限制值的(这个值可以是32M,48M,64M等,根据机型而定),试想一下,如果在app中,增加了一个很常用的图片选择模块用于上传图片或者头像,加载大量Bitmap会使app的内存占用迅速增加,如果你还把查看过的图片缓存在了内存中,那么OOM的风险将会大大增加,如果此时还需要使用WebView加载一波网页,我就问你怕不怕!
 
    微信,微博等主流app是如何解决这些问题的?
 
    微信移动开发团队在 《Android内存优化杂谈》 一文中就说到:“对于webview,图库等,由于存在内存系统泄露或者占用内存过多的问题,我们可以采用单独的进程。微信当前也会把它们放在单独的tools进程中”。
 
    下面我们使用adb查看一下微信和微博的进程信息(Android 5.0以下版本可直接在“设置 -> 应用程序”相关条目中查看):
 
巧用Android多进程,微信,微博等主流App都在用
 
    进入adb shell后,使用 “ps | grep 条目名称” 可以过滤出想要查看的进程。
 
    可以看到,微信的确有一个tools进程,而新浪微博也有image相关的进程,而且它们当中还有好些其它的进程,比如微信的push进程,微博的remote进程等,这里可以看出,他们不单单只是把上述的WebView、图库等放到单独的进程,还有推送服务等也是运行在独立的进程中的。一个消息推送服务,为了保证稳定性,可能需要和UI进程分离,分离后即使UI进程退出、Crash或者出现内存消耗过高等情况,仍不影响消息推送服务。
 
    可见,合理使用多进程不仅仅是有多大好处的问题,我个人认为而且是很有必要的。
 
    所以说,我们最好还是根据自身情况,考虑一下是否需要拆分进程。这也是本文的初衷:给大家提供一个多进程的参考思路,在遇到上述问题和场景的时候,可以考虑用多进程的方法来解决问题,又或者,在面试的时候,跟面试官聊到这方面的知识时候也不至于尴尬。
 
    3.为什么需要“跨进程通讯”?
 
    Android的进程与进程之间通讯,有些不需要我们额外编写通讯代码,例如:把选择图片模块放到独立的进程,我们仍可以使用startActivityForResult方法,将选中的图片放到Bundle中,使用Intent传递即可。(看到这里,你还不打算把你项目的图片选择弄到独立进程么?)
 
    但是对于把“消息推送Service”放到独立的进程,这个业务就稍微复杂点了,这个时候可能会发生Activity跟Service传递对象,调用Service方法等一系列复杂操作。
 
    由于各个进程运行在相对独立的内存空间,所以它们是不能直接通讯的,因为程序里的变量、对象等初始化后都是具有内存地址的,举个简单的例子,读取一个变量的值,本质是找到变量的内存地址,取出存放的值。不同的进程,运行在相互独立的内存(其实就可以理解为两个不同的应用程序),显然不能直接得知对方变量、对象的内存地址,这样的话也自然不能访问对方的变量,对象等。此时两个进程进行交互,就需要使用跨进程通讯的方式去实现。简单说,跨进程通讯就是一种让进程与进程之间可以进行交互的技术。
 
    4.跨进程通讯的方式有哪些?
 
    1.四大组件间传递Bundle;
 
    2.使用文件共享方式,多进程读写一个相同的文件,获取文件内容进行交互;
 
    3.使用Messenger,一种轻量级的跨进程通讯方案,底层使用AIDL实现(实现比较简单,博主开始本文前也想了一下是否要说一下这个东西,最后还是觉得没有这个必要,Google一下就能解决的问题,就不啰嗦了);
 
    4.使用AIDL(Android Interface Definition Language),Android接口定义语言,用于定义跨进程通讯的接口;
 
    5.使用ContentProvider,常用于多进程共享数据,比如系统的相册,音乐等,我们也可以通过ContentProvider访问到;
 
    6.使用Socket传输数据。
 
    接下来本文将重点介绍使用AIDL进行多进程通讯,因为AIDL是Android提供给我们的标准跨进程通讯API,非常灵活且强大(貌似面试也经常会问到,但是真正用到的也不多…)。上面所说的Messenger也是使用AIDL实现的一种跨进程方式,Messenger顾名思义,就像是一种串行的消息机制,它是一种轻量级的IPC方案,可以在不同进程中传递Message对象,我们在Message中放入需要传递的数据即可轻松实现进程间通讯。但是当我们需要调用服务端方法,或者存在并发请求,那么Messenger就不合适了。而四大组件传递Bundle,这个就不需要解释了,把需要传递的数据,用Intent封装起来传递即可,其它方式不在本文的讨论范围。
 
    下面开始对AIDL的讲解,各位道友准备好渡劫了吗?
 
    5.使用AIDL实现一个多进程消息推送
 
    像图片选择这样的多进程需求,可能并不需要我们额外编写进程通讯的代码,使用四大组件传输Bundle就行了,但是像推送服务这种需求,进程与进程之间需要高度的交互,此时就绕不过进程通讯这一步了。
 
    下面我们就用即时聊天软件为例,手动去实现一个多进程的推送例子,具体需求如下:
 
    1.UI和消息推送的Service分两个进程;
 
    2.UI进程用于展示具体的消息数据,把用户发送的消息,传递到消息Service,然后发送到远程服务器
 
    3.Service负责收发消息,并和远程服务器保持长连接,UI进程可通过Service发送消息到远程服务器,Service收到远程服务器消息通知UI进程;
 
    4.即使UI进程退出了,Service仍需要保持运行,收取服务器消息。
 
    6.实现思路
 
    先来整理一下实现思路:
 
    1.创建UI进程(下文统称为客户端);
 
    2.创建消息Service(下文统称为服务端);
 
    3.把服务端配置到独立的进程(AndroidManifest.xml中指定process标签);
 
    4.客户端和服务端进行绑定(bindService);
 
    5.让客户端和服务端具备交互的能力。(AIDL使用);
 
    7.例子具体实现
 
    为了阅读方便,下文中代码将省略非重点部分,可以把本文完整代码Clone到本地再看文章:
 
    https://github.com/V1sk/AIDL
 
    Step0. AIDL调用流程概览
 
    开始之前,我们先来概括一下使用AIDL进行多进程调用的整个流程:
 
    1.客户端使用bindService方法绑定服务端;
 
    2.服务端在onBind方法返回Binder对象;
 
    3.客户端拿到服务端返回的Binder对象进行跨进程方法调用;
 
巧用Android多进程,微信,微博等主流App都在用
 
    整个AIDL调用过程概括起来就以上3个步骤,下文中我们使用上面描述的例子,来逐步分解这些步骤,并讲述其中的细节。
 
    Step1.客户端使用bindService方法绑定服务端
 
    1.1 创建客户端和服务端,把服务端配置到另外的进程
 
    1.创建客户端 -> MainActivity;
 
    2.创建服务端 -> MessageService;
 
    3.把服务端配置到另外的进程 -> android:process=”:remote”
 
    上面描述的客户端、服务端、以及把服务端配置到另外进程,体现在AndroidManifest.xml中,如下所示:
 
巧用Android多进程,微信,微博等主流App都在用
 
    开启多进程的方法很简单,只需要给四大组件指定android:process标签。
 

责任编辑:李欢
本文为授权转载文章,任何人未经原授权方同意,不得复制、转载、摘编等任何方式进行使用,e-works不承担由此而产生的任何法律责任! 如有异议请及时告之,以便进行及时处理。联系方式:editor@e-works.net.cn tel:027-87592219/20/21。
e-works
官方微信
掌上
信息化
编辑推荐
新闻推荐
博客推荐
视频推荐