Android IPC之 Service和Messenger

IPC机制是Android的重要组成部分,本文介绍其中的Service和Messenger。结合模拟的支付调用作为例子,翔实明了,简直不能再良心。

IPC(进程间通信)

Interprocess Communication

Service

A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use.

可以看到主要有两点是比较有特点的:不可见并且和用户长时间交互、为其他应用程序提供服务。

Service可以脱离Activity的生命周期独立存在。不过,有一点看上去Service要比Thread“弱”一些:Service一般是不会在新的线程中运行,如果里面进行了耗时操作的话,还是需要新开线程的。

Service主要分为应用程序内部使用的Local Service 和 进行IPC的Remote Messenger Service(含AIDL)。

作用

  • A facility for the application to tell the system about something it wants to be doing in the background (even when the user is not directly interacting with the application). This corresponds to calls to Context.startService(), which ask the system to schedule work for the service, to be run until the service or someone else explicitly stop it.

    应用程序告诉操作系统要在后台处理些事情。

  • A facility for an application to expose some of its functionality to other applications. This corresponds to calls to Context.bindService(), which allows a long-standing connection to be made to the service in order to interact with it.

    向其他应用程序暴露自己的一些功能,即跨进程通信。

Service的启动

bindService(Intent service, ServiceConnection conn, int flags);
  • service,要绑定的那个Service

  • coon,这个接口有两个方法,对应service的bind和unbind两个节点。bindService是异步的,onServiceConnected() 作为绑定成功的回调。

  • flag,设置绑定的模式,如BIND_AUTO_CREATE

    bindService()会立即返回空值,ServiceonBinder()返回Binder时回调ServiceConnection的onServiceConnected()方法,并将该Binder作为参数传入。

startService(Intent service)

使用 bindService()启动Service,在Service失去所有绑定后将执行onDestroy()

只要使用了startService()方法(执行onCreate的调用或者在bind之后的调用),Service不会在Activity退出后stop。

Lifecycle of Service

IBinder/Binder

远程对象的基本接口,为进行高性能的进程内/间调用而设计的轻量级远程调用机制的核心部分。这个接口描述了与远程对象进行交互的抽象协议。一般使用的时候从Binder继承,不要直接implement这个接口。

IBinder onBind();

真正的通信部分由Binder完成。API文档中有更具体的描述

一般来说,对于一个仅仅在应用程序内部使用的Service我们可以拓展Binder,添加getService()这个方法,来达到暴露Service内部功能的目的。但是对于进程间的调用来说这样就很难行得通了(本地没有对应的class文件,不知道Service里面到底添加了哪些方法),所以,自上而下,来看Messenger。

Messenger

这个类的注释文档中写道:

Reference to a Handler, which others can use to send messages to it. This allows for the implementation of message-based communication across processes, by creating a Messenger pointing to a Handler in one process, and handing that Messenger to another process.

Note: the implementation underneath is just a simple wrapper around a {@link Binder} that is used to perform the communication.

引用,指向一个Handler。可以被用来发送消息(充当信使/邮差的功能)。通过在一个进程创造一个指向Handler的Messenger并且把这个Messenger传递到另一个进程,来允许基于Message的进程间通信。

注意:这个类的底层是对Binder的一个简单封装,Binder是用来执行通信的。(这个类的结构很简单,里面封装了一些Binder的行为)

虽然把这些名称翻译成中文挺奇怪的,但是找到这些类在现实生活中的映射对于更好的理解有很大帮助。Messenger,译作“信使”,应该是古代负责传递消息的使节或衙役之类的人物。在IPC机制中起到的作用就应该是传递信息,比如Service持有一个Messenger,通过这个Messenger发送消息。

Constructor

new Messenger(IBinder/Handler target); //IBinder-Client / Handler-Service

构造方法可以接收两种参数,也分别对应了两种情形:

  • IBinder

    在绑定Activity的时候,bindService()要求一个参数ServiceConnection,而绑定成功的回调结果就是一个Binder(由Service的onBind()返回)。

    这个构造方法一般是用在请求绑定的一端,构造出来的Messenger向Service发送Message

  • Handler

    Handler作为Android里的跨线程机制的重要组成部分,和Message一直有着密不可分的关系。它的作用就是handle一些东西(Message),而在Service的使用中,一般是由请求端向Service端发出一个请求(信息包含在Message里)。这也就意味着,在引入Messenger的情况下,Service中要包含一个Handler用来处理发过来的请求。

    这个构造方法一般用在Service端,将Handler和Messenger链接起来。

以上两个构造方法完成了Messenger的传递。


具体过程

Messenger的主要作用过程如下:

  1. Messenger在Service中以Handler以参数创建

    Messenger mMessenger = new Messenger(new PaymentHandler()); //Simple Sample
    
  2. Service被绑定后,发起绑定的一方用Binder为参数创建。

    Service中返回Messenger的Binder:

    @Override
        public IBinder onBind(Intent intent) {
            Log.i(TAG, "onBind");
            return mMessenger.getBinder();
        }
    

    Activity(eg.)中获取并实例化:

    ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //来自Service的Messenger
                Messenger messenger = new Messenger(service);
                ......
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                ......
            }
        };
    
  3. 进行通信:

    Message msg = Message.obtain();
    //fill your info into msg
    messenger.send(msg);
    

实现双向的消息发送

在ServiceConnection的onServiceConnected()里面发送一个Message,具体过程如下:

  • new 一个Handler,负责处理Service发过来的消息
  • 用这个Handler创建一个Messenger
  • 发送一个Message,replyTo设置为刚才创建的Messenger

一个实例:

​ 模拟一个支付调用,简单得有些简陋。

​ 一侧:

@SuppressLint("HandlerLeak")
            Handler responseHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                  //打印支付结果
                    Log.i(TAG, "handleMessage: Response from Service");
                    Log.i(TAG, "handleMessage: " + msg.obj);
                }
            };
            msg.replyTo = new Messenger(responseHandler);

//发起支付请求
            msg.obj = "I request to pay $233.33.";
            try {
                messenger.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

​ 另一侧:

public void handleMessage(Message msg) {
  //打印支付的消息内容
            Log.i(TAG, "handleMessage: " + msg.obj);
            try {
              //模拟支付成功的回调
                Message reply = Message.obtain();
                reply.obj = "Payment Success!";
                msg.replyTo.send(reply);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

打印出来的Log如下:

I/IPC:LocalService: onCreate
I/IPC:LocalService: Received start id 1: Intent { cmp=com.boileryao.ipc/.LocalService }
I/IPC:LocalService: onBind
I/IPC:LocalService: handleMessage: I request to pay $233.33.
I/ContentValues: handleMessage: Response from Service
I/ContentValues: handleMessage: Payment Success!

Happy Coding :)

via 锅炉工

ref:

Android Developer :: Service

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

推荐阅读更多精彩内容