Android进程间通信

开启多进程模式

在Android中开启多进程只有一种方法,就是给四大组件(Activity、Service、Receiver、ContentProvider)在AndroidMenifest中指定android:process属性。

序列化

通过Intent和Binder传数据时,需要使用Serializable或者Parcelable,数据持久化也需要Serializable。

系统提供的Parcelable接口的类:Intent、Bundle、Bitmap,List和Map也可以序列化,前提是每个元素都是可序列化的。

所以通信的数据自定义格式基本上都需要序列化

Binder

binder.png

Android开发中,Binder主要用在Service中,包括AIDL及Messenger。普通Service中的Binder不涉及进程间通信,Messenger的底层其实是AIDL。

Android中的IPC方式

使用Bundle

在Bundle中附加需要传输给远程的数据并通过Intent发送出去

使用共享文件

A进程把数据写入文件,B进程通过读取这个文件来获取数据。可以是文本,xml,也可以是自定义的。SharedPreferences由于在内存中会有一份缓存,所以多进程时不建议使用。

使用Messenger

通过它可以在不同进程中传递Message对象,它的底层实现是AIDL,它一次处理一个请求,因此服务端不用考虑线程同步问题。
实现步骤:

  • 服务端进程
    在服务端创建一个Service来处理客户端的连接请求,同时创建一个Handler并通过它创建一个Messenger对象,然后在Service的onBind中返回这Messenger对象底层的Binder即可。
private final Messenger mMessenger=new Messenger(new MyHandler());
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
  • 客户端进程
    首先绑定服务端的Service,绑定成功后,用服务端返回的IBinder创建一个Messenger,通过这个Messenger就可以向服务端发送消息了。
private Messenger mService;
    //
    private ServiceConnection mConn=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mService=new Messenger(iBinder);
            Message msg= Message.obtain(null, MyConstants.MSG_FROM_CLIENT);
            Bundle bundle=new Bundle();
            bundle.putString("msg","client is connect");
            msg.setData(bundle);

            try {
                mService.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
        }
    };

    //服务端的回调
    private Messenger mReplyMessenger=new Messenger(new ReplyHandler());
    private static class ReplyHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MyConstants.MSG_FROM_SERVICE:
                    Log.d(TAG,"receive msg from service:"+msg.getData().getString("msg"));
                    break;
                default:
                    super.handleMessage(msg);
                    break;
            }
        }
    }
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenger);

        Intent intent=new Intent(this,MessengerService.class);

        bindService(intent,mConn, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        unbindService(mConn);
        super.onDestroy();
    }

使用AIDL

Messenger本质是AIDL实现,主要是为了传递消息,无法处理大量并发。另外无法做到调用服务端方法。
AIDL通信流程:

  1. 服务端
    创建一个服务端来监听客户端的请求,然后创建AIDL文件,将给客户端的接口在这个文件中声明,在Service中实现这个AIDL接口。
  • 处理并发请求,所以要用CopyOnWriteArrayList
  • Binder会把传过来的对象重新生成新对象,RemoteCallbackList是系统提供的用于删除进程Listener的接口,内部实现线程同步,用它来注册及解注册。
  1. 客户端
    绑定服务端的Service,将服务端返回的Binder对象转换成AIDL接口所属的类型,然后就可以调用AIDL中的方法了。
  • 调用的方法可能是耗时操作,最好是在线程中去调用
  1. AIDL接口的创建

AIDL文件支持的数据类型:
基本类型(int ,long, char, boolean, double等)
StringCharSequence;
List: 只支持ArrayList (里面每个元素都必须支持)
Map: 只支持HashMap(key,value每个元素都必须支持)
Parcelable: 所有实现了Parcelable接口的对象
AIDL: 所有AIDL接口本身也可以在AIDL文件中使用。

由于代码相对较多,请在文末链接去查看实现代码。

注意点:

  • Parcelable对象和AIDL对象必须显示import进来
  • AIDL文件中用到的Parcelable对象,必须新建一个和它同名的AIDL文件,并在其中声明为Parcelable类型

使用ContentProvider

创建一个自定义的ContentProvider只需继承ContentProvider并实现6个接口方法即可。

使用Socket

建立一个ServerSocket当服务端,再建立一个Socket当客户端去连接,它们通过本地网络来进行通信。

使用场景比较

一个表格来说明优缺点及使用场景

名称 优点 缺点 适用场景
Bundle 简单易用 只能传输Bundle支持的数据 四大组件间通信
文件共享 简单易用 不适合高并发,不能即时通信 无并发,简单交换数据
AIDL 功能强大,支持一对多,实时通信 使用复杂,需处理好了线程同步 有一对多,远程调用的需求
Messenger 支持一对多串行通信,支持实时通信 不支持高并发,不支持远程调用,只能传递Bundle数据 低并发一对多即时通信,无远程调用需求,或无须返回结果的远程调用
ContentProvider 数据访问方面功能强大,支持一对多并发数据共享,可通过Call方法扩展其它操作 可理解为受约束的AIDL,主要提供CRUD操作 一对多的进程间的数据共享
Socket 功能强大,通过网络传输字节流,支持一对多并发实时通信 实现烦琐,不支持直接的远程调用 网络数据交换

最后给出Messenger,AIDL及Socket通信的完整示例,可以移步github

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容