Android开发高级进阶——多进程间通信
一. 什么是多进程?
多进程就是多个进程的意思,那么什么是进程呢?
当一个应用在开始运行时,系统会为它创建一个进程,一个应用默认只有一个进程,这个进程(主进程)的名称就是应用的包名。
进程的特点:
- 进程是系统资源和分配的基本单位,而线程是调度的基本单位。
- 每个进程都有自己独立的资源和内存空间
- 其它进程不能任意访问当前进程的内存和资源
- 系统给每个进程分配的内存会有限制
根据上边的引言和进程的特点可以看出,使用多进程的场景为:需要使apk所使用的内存限制扩大。
二. 进程的等级
按优先级可以分为五类,优先级从高到低排列:

- 前台进程:该进程包含正在与用户进行交互的界面组件,比如一个Activity。在接收关键生命周期方法时会让一个进程临时提升为前台进程,包括任何服务的生命周期方法onCreate()和onDestroy()和任何广播接收器onReceive()方法。这样做确保了这些组件的操作是有效的原子操作,每个组件都能执行完成而不被杀掉。
- 可见进程:该进程中的组件虽然没有和用户交互,但是仍然可以被看到。activity可见的时候不一定在前台。一个简单的例子是前台的 activity 使用对话框启动了一个新的 activity 或者一个透明 activity 。另一个例子是当调用运行时权限对话框时(事实上它就是一个 activity!)。
- 服务进程:该进程包含在执行后台操作的服务组件,比如播放音乐的Service。对于许多在后台做处理(如加载数据)而没有立即成为前台服务的应用都属于这种情况。
请特别注意从onStartCommand()返回的常量,如果服务由于内存压力被杀掉,它表示控制什么发生什么:
START_STICKY表示希望系统可用的时候自动重启服务,但不关心是否能获得最后一次的 Intent (例如,可以重建自己的状态或者控制自己的 start/stop 生命周期)。
START_REDELIVER_INTENT是为那些在被杀死之后重启时重新获得 Intent 的服务的,直到用传递给 onStartCommand() 方法的 startId 参数调用stopSelf()为止。这里会使用 Intent 和 startId 作为队列完成工作。
START_NOT_STICKY用于那些杀掉也没关系的服务。这适合那些管理周期性任务的服务,它们只是等待下一个时间窗口工作。 - 后台进程:该进程包含的组件没有与用户交互,用户也看不到 Service。在一般操作场景下,设备上的许多内存就是用在这上面的,使可以重新回到之前打开过的某个 activity 。
- 空进程:没有任何界面组件、服务组件,或触发器组件,只是出于缓存的目的而被保留(为了更加有效地使用内存而不是完全释放掉),只要 Android 需要可以随时杀掉它们。
三. 多进程的创建
Android多进程创建很简单,只需要在AndroidManifest.xml的声明四大组件的标签中增加”android:process”属性即可。命名之后,就成了一个单独的进程。
process分私有进程和全局进程:
- 私有进程的名称前面有冒号,例如:
<service android:name=".MusicService"
android:process=":musicservice"/>
- 全局进程的名称前面没有冒号,例如:
<service android:name=".MusicService"
android:process="com.trampcr.musicdemo.service"/>
为了节省系统内存,在退出该Activity的时候可以将其杀掉(如果没有人为杀掉该进程,在程序完全退出时该进程会被系统杀掉)。
多进程被创建好了,应用运行时就会对进程进行初始化,如果一个application中有多个进程,在进行全局初始化时,多进程会被初始化多次。
解决办法:判断当前进程,然后做相应的初始化操作。
四. 多进程间的通信IPC
IPC:InterProcess Communication,即进程间通信。
我们知道,同一个进程的多个线程是共享该进程的所有资源,但多个进程间内存是不可见的,也就是说多个进程间内存是不共享的。那么进程间是如何进行通信的呢?
Android中提供了三种方法:
- 系统实现。
- AIDL(Android Interface Definition Language,Android接口定义语言):大部分应用程序不应该使用AIDL去创建一个绑定服务,因为它需要多线程能力,并可能导致一个更复杂的实现。
- Messenger:利用Handler实现。(适用于多进程、单线程,不需要考虑线程安全),其底层基于AIDL。
使用Messenger
如需让服务与远程进程通信,则可使用Messenger为服务提供接口。
定义一个MessengerService继承自Service,并在AndroidManifest.xml中声明并给一个进程名,使该服务成为一个单独的进程。代码如下:
MessengerService.java
public class MessengerService extends Service{
class IncomingHandler extends Handler{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 0:
Toast.makeText(getApplicationContext(), "hello, trampcr", Toast.LENGTH_SHORT).show();
break;
}
}
}
Messenger mMessenger = new Messenger(new IncomingHandler());
@Nullable
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
AndroidManifest.xml文件的配置如下:
<service android:name=".MessengerService"
android:process="com.trampcr.messenger.service"/>
MessengerActivity.java
public class MessengerActivity extends Activity{
private boolean mBound;
private Messenger mMessenger;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMessenger = new Messenger(service);
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mMessenger = null;
mBound = false;
}
};
public void sayHello(View v){
if(!mBound){
return;
}
Message msg = Message.obtain(null, 0 , 0, 0);
try {
mMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
}
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(MessengerActivity.this, MessengerService.class);
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
if(mBound){
unbindService(mServiceConnection);
mBound = false;
}
}
}
通过以上代码,可以看到Messenger的使用方法:
- 服务实现一个Handler,由其接收来自客户端的每个调用的回调。
- Handler用于创建Messenger对象(对Handler的引用)。
- Messenger创建一个IBinder,服务通过onBind()使其返回客户端。
- 客户端使用IBinder将Messenger(引用服务的Handler)实例化,然后使用后者将Message对象发送给服务。
- 服务在其Handler中(具体地讲,是在handleMessage()方法中)接收每个Message。
这样,客户端并没有调用服务的“方法”。而客户端传递的“消息”(Message对象)是服务在其Handler中接收的。
以上代码实现的应用,刚打开会弹出一个binding,binding表示打开应用Activity就通过Messenger连接了一个服务进程,然后点击say hello会弹出hello,trampcr,这表示了Activity通过Messenger将Message发送给了服务进程。如下图:

使用AIDL
AIDL是一种接口描述语言,通常用于进程间通信。
使用AIDL的步骤:
- 创建AIDL,在main下新建一个文件夹aidl,然后在aidl下新建AIDL文件,这时系统会自动为该文件创建一个包名。
aidl文件中会有一个默认的basicType方法,我们为它增加一个getName方法。代码如下:
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
String getName(String nickName);
}
以上是我们自己创建的aidl文件,系统还会自动生成aidl代码,所在位置为:build/generated/source/aidl下debug和release,但是此时debug下没有任何东西,可以rebuild或运行一下程序,再次打开debug,发现生成了一个包和一个aidl文件。
- 在java下新建一个类AIDLService继承自Service。代码如下:
public class AIDLService extends Service {
IMyAidlInterface.Stub mStub = new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public String getName(String nickName) throws RemoteException {
return "aidl " + nickName;
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mStub;
}
}
- 在AndroidManifest.xml中注册,并给一个进程名,是该服务成为一个独立的进程。
<service android:name=".AIDLService"
android:process="com.aidl.test.service"/>
- 在MainActivity中进行与AIDLService之间的进程间通信。代码如下:
public class MainActivity extends AppCompatActivity {
private Button mBtnAidl;
private IMyAidlInterface mIMyAidlInterface;
ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtnAidl = (Button) findViewById(R.id.btn_aidl);
bindService(new Intent(MainActivity.this, AIDLService.class), mServiceConnection, BIND_AUTO_CREATE);
mBtnAidl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mIMyAidlInterface != null){
try {
String name = mIMyAidlInterface.getName("I'm nick");
Toast.makeText(MainActivity.this, "name = " + name, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
}
在Activity中利用bindService与AIDLService进行连接,通过IMyAidlInterface实例与AIDLService进程进行通信,如下图所示:

五.序列化插件
Parcelable code generate:自动生成实现了Parcelable接口的对象。
作者:trampcr
链接:https://www.jianshu.com/p/ce1e35c84134
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Android开发高级进阶——多进程间通信的更多相关文章
- Android开发的进阶之路
客户端开发工程师,简单地从某几个方面描述一下个人理解里不同的等级: 1.初级的可以熟练使用系统框架提供的组件,搭建所需应用程序: 2.中级的,会对系统框架中如view绘制.broadcast机制.内存 ...
- 【Mood-12】Android开发相关书籍推荐
新年伊始,找到Android进阶干货若干,2015拜读. 1.Android应用UI设计模式 目前,谷歌Android操作系统在移动市场中风头正劲,并且未来发展势不可挡.<Android应用UI ...
- Android开发工具: AS, Gradle, Git等
(一)史上最详细的Android Studio系列教程 你还没有使用Android Studio + Gradle么?那就有点太落伍了,下面自己原创总结了Android Studio的一系列教程,图文 ...
- Android开发技术周报
Android开发技术周报 原文 http://androidweekly.cn/android-dev-weekly-issue48/ 教程 深入理解Android之Gradle Gradle是当 ...
- Android开发面试经——4.常见Android进阶笔试题(更新中...)
Android开发(29) 版权声明:本文为寻梦-finddreams原创文章,请关注:http://blog.csdn.net/finddreams 关注finddreams博客:http:/ ...
- 《Android高级进阶》读书笔记
<Android高级进阶>是据我所知的市面上唯一一本技术工具书,比较的高大全,作者的目的是为了对全领域有个初步的概念 No1: 在Android系统中,拥有事件传递处理能力的类有以下三种 ...
- 推荐扔物线的HenCoder Android 开发进阶系列 后期接着更新
官网地址:http://hencoder.com/ 我来做一次辛勤的搬运工 HenCoder:给高级 Android 工程师的进阶手册 HenCoder Android 开发进阶: 自定义 View ...
- android开发进阶学习博客资源
Android开发者博客推荐 Android入门级 - 罗宪明 http://blog.csdn.net/wdaming1986 Android入门级 - 魏祝林 http://blog.csdn.n ...
- 《android开发进阶从小工到专家》读书笔记--HTTP网络请求
No1: 客户端与服务器的交互流程: 1)客户端执行网络请求,从URL中解析出服务器的主机名 2)将服务器的主机名转换成服务器的IP地址 3)将端口号从URL中解析出来 4)建立一条从客户端与Web服 ...
随机推荐
- CountDownLatch源码浅析
Cmd Markdown链接 CountDownLatch源码浅析 参考好文: JDK1.8源码分析之CountDownLatch(五) Java并发之CountDownLatch源码分析 Count ...
- resteasy json
https://www.cnblogs.com/toSeeMyDream/p/5763725.html
- C# 实现动态添加列,新增合计行,求和
DataTable da = CommonBLL.GetList("*", "sys_dict", "IfState=1 and DictTypeId ...
- c# 发送web请求
我们目前涉及到的现有的接收请求方式有三种, 第一种: 页面式的Form表单 第二种: 服务的webservice形式的xml 第三个: restful风格的post包体json 第一种比较老,博客园的 ...
- Entity Framework中使用DbCompiledModel中遇到的坑和解决方案
前段时间,在公司做项目时,引入Entity Framework Code First的方法. 我们公司的软件为SaaS结构,有N个企业注册,其中SQL Server中有一张表为t_User_企业注册号 ...
- sql 触发器 游标
在数据库中,删除一条记录的同时想要删除另一个表里的数据,这时我们可以选择使用触发器.触发器主要是通过事件进行触发被自动调用执行的,而存储过程可以通过存储过程的名称被调用.触发器是当对某一个表进行操作. ...
- [jquery] 遍历select的option,然后设置一项为选中
<script> var v={$menu.pid}; $("#pid option").each(function(){ if($(this).val()==v){ ...
- Bzoj1486/洛谷P3199 最小圈(0/1分数规划+spfa)/(动态规划+结论)
题面 Bzoj 洛谷 题解(0/1分数规划+spfa) 考虑\(0/1\)分数规划,设当前枚举到的答案为\(ans\) 则我们要使(其中\(\forall b_i=1\)) \[ \frac{\sum ...
- 最近公共祖先LCA(前置知识)
1.前言 最近公共祖先(Least Common Ancestors),简称LCA,是由Tarjan教授(对,又是他)提出的一种在有根树中,找出某两个结点u和v最近的公共祖先问题. 2.什么是最近公共 ...
- 第八届山东省ACM大学生程序设计竞赛个人总结
因为省赛,从开学紧张到5月7号.心思也几乎全放在ACM的训练上.因为我还是校台球协会的会长,所以台协还有一些事情需要忙,但是我都给延迟了.老会长一直在催我办校赛,但我一直说 等等吧,因为校赛只能在周六 ...