Smart use of Android multi-process, mainstream apps such as WeChat and Weibo are in use

foreword

As for the concept of process, all the people who come here are people who are programming and cultivating immortals, so they will no longer be verbose. I believe that everyone can memorize it backwards, jumping, lying down, and various postures.

Why use multi-process, can't one process be enough?

I believe that many students basically do not divide the process for the app in actual development. Moreover, using multiple processes in Android may require writing additional process communication code, which may also bring additional bugs, which undoubtedly increases The workload of development is not allowed in many startups, which leads to the fact that the entire app is in one process.

What are the disadvantages of having the entire app in one process?
In Android, the running memory allocated by the virtual machine to each process has a limited value (this value can be 32M, 48M, 64M, etc., depending on the model), just imagine, if you add a very commonly used one in the app The picture selection module is used to upload pictures or avatars. Loading a large number of Bitmaps will rapidly increase the memory usage of the app. If you also cache the viewed pictures in the memory, the risk of OOM will be greatly increased. If you need to use WebView to load a wave of web pages, I will ask you if you are afraid!

How do mainstream apps such as WeChat and Weibo solve these problems?
Wechat mobile development team said in  the article "Android Memory Optimization Talk"  : "For webview, gallery, etc., due to the problem of memory system leakage or excessive memory usage, we can use separate processes. Wechat will also use them at present. in a separate tools process".

Let's use adb to view the process information of WeChat and Weibo (for versions below Android 5.0, you can view it directly in the related items of "Settings -> Applications"):


Once in the adb shell, use "ps | grep entry name" to filter out the processes you want to see.
It can be seen that WeChat does have a tools process, and Sina Weibo also has image-related processes, and there are many other processes among them, such as WeChat's push process, Weibo's remote process, etc. It can be seen here that they Not only the above-mentioned WebView, gallery, etc. are placed in a separate process, but also the push service, etc. are also running in a separate process. A message push service may need to be separated from the UI process in order to ensure stability. After separation, even if the UI process exits, crashes, or excessive memory consumption occurs, the message push service will not be affected.

It can be seen that the rational use of multi-process is not only a matter of how good it is, but I personally think it is necessary.

Therefore, it is best for us to consider whether we need to split the process according to our own situation. This is also the original intention of this article: to provide you with a multi-process reference idea. When encountering the above problems and scenarios, you can consider using a multi-process method to solve the problem, or, during the interview, talk to the interviewer. This knowledge is not embarrassing.

Why do you need "cross-process communication"?

Android's process-to-process communication, some do not require us to write additional communication code, for example: put the selected image module into a separate process, we can still use the startActivityForResult method, put the selected image into the Bundle, and use the Intent to pass it. Can. (Seeing this, don't you plan to make the image selection of your project a separate process?)

But for putting the "message push service" into a separate process, this business is a little more complicated. At this time, a series of complex operations such as Activity and Service passing objects, calling Service methods, etc. may occur.

由于各个进程运行在相对独立的内存空间,所以它们是不能直接通讯的,因为程序里的变量、对象等初始化后都是具有内存地址的,举个简单的例子,读取一个变量的值,本质是找到变量的内存地址,取出存放的值。不同的进程,运行在相互独立的内存(其实就可以理解为两个不同的应用程序),显然不能直接得知对方变量、对象的内存地址,这样的话也自然不能访问对方的变量,对象等。此时两个进程进行交互,就需要使用跨进程通讯的方式去实现。简单说,跨进程通讯就是一种让进程与进程之间可以进行交互的技术。

跨进程通讯的方式有哪些?

  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的讲解,各位道友准备好渡劫了吗?

使用AIDL实现一个多进程消息推送

像图片选择这样的多进程需求,可能并不需要我们额外编写进程通讯的代码,使用四大组件传输Bundle就行了,但是像推送服务这种需求,进程与进程之间需要高度的交互,此时就绕不过进程通讯这一步了。
下面我们就用即时聊天软件为例,手动去实现一个多进程的推送例子,具体需求如下:

  1. UI和消息推送的Service分两个进程;
  2. UI进程用于展示具体的消息数据,把用户发送的消息,传递到消息Service,然后发送到远程服务器;
  3. Service负责收发消息,并和远程服务器保持长连接,UI进程可通过Service发送消息到远程服务器,Service收到远程服务器消息通知UI进程;
  4. 即使UI进程退出了,Service仍需要保持运行,收取服务器消息。

实现思路

先来整理一下实现思路:

  1. 创建UI进程(下文统称为客户端);
  2. 创建消息Service(下文统称为服务端);
  3. 把服务端配置到独立的进程(AndroidManifest.xml中指定process标签);
  4. 客户端和服务端进行绑定(bindService);
  5. 让客户端和服务端具备交互的能力。(AIDL使用)

例子具体实现

为了阅读方便,下文中代码将省略非重点部分,可以把本文完整代码Clone到本地再看文章:
https://github.com/V1sk/AIDL

Step0. AIDL调用流程概览

开始之前,我们先来概括一下使用AIDL进行多进程调用的整个流程:

  1. 客户端使用bindService方法绑定服务端;
  2. 服务端在onBind方法返回Binder对象;
  3. 客户端拿到服务端返回的Binder对象进行跨进程方法调用;
    AIDL calling process

    AIDL调用过程


    整个AIDL调用过程概括起来就以上3个步骤,下文中我们使用上面描述的例子,来逐步分解这些步骤,并讲述其中的细节。

Step1.客户端使用bindService方法绑定服务端

1.1 创建客户端和服务端,把服务端配置到另外的进程
  1. 创建客户端 -> MainActivity;
  2. 创建服务端 -> MessageService;
  3. 把服务端配置到另外的进程 -> android:process=”:remote”

上面描述的客户端、服务端、以及把服务端配置到另外进程,体现在AndroidManifest.xml中,如下所示:

 
     
1
2
3
4
5
6
7
8
9
10
11
12
13
 
     
<manifest ...>
<application ...>
<activity android:name=".ui.MainActivity"/>
<service
android:name= ".service.MessageService"
android:enabled= "true"
android:exported= "true"
android:process= ":remote" />
</application>
</manifest>

开启多进程的方法很简单,只需要给四大组件指定android:process标签。

1.2 绑定MessageService到MainActivity

创建MessageService
此时的MessageService就是刚创建的模样,onBind中返回了null,下一步中我们将返回一个可操作的对象给客户端。

 
     
1
2
3
4
5
6
7
8
9
10
11
 
     
public class MessageService extends Service {
public MessageService() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

客户端MainActivity调用bindService方法绑定MessageService
这一步其实是属于Service组件相关的知识,在这里就比较简单地说一下,启动服务可以通过以下两种方式:

  1. 使用bindService方法 -> bindService(Intent service, ServiceConnection conn, int flags);
  2. 使用startService方法 -> startService(Intent service);

bindService & startService区别:
使用bindService方式,多个Client可以同时bind一个Service,但是当所有Client unbind后,Service会退出,通常情况下,如果希望和Service交互,一般使用bindService方法,使用onServiceConnected中的IBinder对象可以和Service进行交互,不需要和Service交互的情况下,使用startService方法即可。

正如上面所说,我们是要和Service交互的,所以我们需要使用bindService方法,但是我们希望unbind后Service仍保持运行,这样的情况下,可以同时调用bindService和startService(比如像本例子中的消息服务,退出UI进程,Service仍需要接收到消息),代码如下:

 
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 
     
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);
setupService();
}
/**
* unbindService
*/
@Override
protected void onDestroy() {
unbindService(serviceConnection);
super.onDestroy();
}
/**
* bindService & startService
*/
private void setupService() {
Intent intent = new Intent( this, MessageService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
startService(intent);
}
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected");
}
};
}

Stpe2.服务端在onBind方法返回Binder对象

2.1 首先,什么是Binder?

要说Binder,首先要说一下IBinder这个接口,IBinder是远程对象的基础接口,轻量级的远程过程调用机制的核心部分,该接口描述了与远程对象交互的抽象协议,而Binder实现了IBinder接口,简单说,Binder就是Android SDK中内置的一个多进程通讯实现类,在使用的时候,我们不用也不要去实现IBinder,而是继承Binder这个类即可实现多进程通讯。

2.2 其次,这个需要在onBind方法返回的Binder对象从何而来?

Here we will introduce the theme of this article -
the Binder object used in AIDL multi-process, which is generally automatically generated through the .adil interface file we defined. Of course, you can go the wild way and manually write the required cross-process communication. The essence of the Binder class is nothing more than a class that inherits Binder. Since the wild way is troublesome, and it is a work of repeated steps, Google provides the AIDL interface to help us automatically generate Binder. The right way, in the following we focus on AIDL Continue to discuss this right path (you can't lead people astray, right?

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325979444&siteId=291194637