Handler进程间通信

来源:互联网 发布:搜狐网络大厦it 编辑:程序博客网 时间:2024/06/07 05:16

          Handler在线程间通信很常用,进程间通信却用的很少,书中有介绍自己试用了一下,觉得不是很好用,而且底层也是AIDL,也是Binder,其实没差别,还很绕。

 客户端为一个Acitvity 代码如下


package com.xue.qin.demo.message;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.support.annotation.Nullable;import android.util.Log;import android.view.View;import android.widget.Button;/** * Created by xue.qin on 2017/6/12. */public class ClientActivity extends Activity implements View.OnClickListener {    private static final String TAG = "ClientActivity";    Button mButton;    private Messenger mService;    private Messenger mMessenger = new Messenger(new Handler() {        @Override        public void handleMessage(Message msgFromServer) {            Log.i(TAG, "Client Get Message :" + msgFromServer);            super.handleMessage(msgFromServer);        }    });    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.mai_activity_layout);        mButton = (Button) findViewById(R.id.sendMessage);        mButton.setOnClickListener(this);        Intent startService = new Intent("remoteService");        startService.setPackage(getPackageName());        bindService(startService, mConn, Context.BIND_AUTO_CREATE);    }    private ServiceConnection mConn = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            mService = new Messenger(service);            Log.i(TAG, "onServiceConnected()");        }        @Override        public void onServiceDisconnected(ComponentName name) {            mService = null;            Log.i(TAG, "onServiceDisconnected()");        }    };    @Override    protected void onDestroy() {        unbindService(mConn);        super.onDestroy();    }    @Override    public void onClick(View v) {        try {            if (mService != null) {                Message msg = Message.obtain(); //从消息池中取出最靠前的消息,如果没有消息就新建一个,然后重新赋值                msg.what = 1234;                msg.arg1 = 1;                msg.arg2 = 2;                msg.replyTo = mMessenger;                mService.send(msg);            }        } catch (RemoteException e) {            e.printStackTrace();        }    }}

在声明一个服务端的Service,是在不同进程Xml写成如下

<service            android:name=".ServerService"            android:process=".remote">            <intent-filter>                <action android:name="remoteService"></action>            </intent-filter>        </service>


Service代码如下:

package com.xue.qin.demo.message;import android.app.Service;import android.content.Intent;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.support.annotation.Nullable;import android.util.Log;/** * Created by xue.qin on 2017/6/12. */public class ServerService extends Service {    private static final String TAG = "ServerService";    Messenger mMessenger = new Messenger(new Handler() {        @Override        public void handleMessage(Message fromClient) {            Log.i(TAG, "msg = " + fromClient);            try {                Message toClient = Message.obtain();                toClient.what = 1234;                toClient.arg1 = fromClient.arg1 + 1;                toClient.arg2 = fromClient.arg2 + 1;                fromClient.replyTo.send(toClient);            } catch (RemoteException e) {                e.printStackTrace();            }            super.handleMessage(fromClient);        }    });    @Nullable    @Override    public IBinder onBind(Intent intent) {        return mMessenger.getBinder();    }}



因为是AIDL,本质应该是相同的,那么走一遍AIDL的流程,就明白了。

1)绑定Service。

2)返回onBind() 返回 Binder,这里和AIDL不一样是Messenger获得的BInder,去看一下源码是怎么回事。

Messenger.java

public Messenger(Handler target) {        mTarget = target.getIMessenger();    }

Messenger的声明实例使用了这个构造函数, 去看一下Handler里个getIMessenger()。

Handler.java

final IMessenger getIMessenger() {        synchronized (mQueue) {            if (mMessenger != null) {                return mMessenger;            }            mMessenger = new MessengerImpl();            return mMessenger;        }    }

这里new的这个内部类是这样的。

private final class MessengerImpl extends IMessenger.Stub {        public void send(Message msg) {            msg.sendingUid = Binder.getCallingUid();            Handler.this.sendMessage(msg);        }    }

这个就是是AIDL的生成的BInder类,native方法,没去看了。可以肯定的是这里的参数msg就是到底层转了一圈回来的客户端msg。

那它一定有个aidl文件,叫IMessenger.aidl,这个Handler类都没有引用包,那么应该就在同一个包里面了,果然找到了,代码如下。

文件位置:alps/frameworks/base/core/java/android/os


/* //device/java/android/android/app/IActivityPendingResult.aidl**** Copyright 2007, The Android Open Source Project**** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ****     http://www.apache.org/licenses/LICENSE-2.0 **** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License.*/package android.os;import android.os.Message;/** @hide */oneway interface IMessenger {    void send(in Message msg);}

隐藏的接口,其中AIDL的方法还提供了oneway这个关键字,可以用关键字oneway来标明远程调用的行为属性,使用了该关键字,那么远程调用将仅仅是调用所需的数据传输过来并立即返回,而不会等待结果的返回,也即是说不会阻塞远程线程的运行。

这点和没有标记oneway的挂起等待返回,是不一样的。

就一个方法 send(),再往后就是BInder转发了,好的到这知道服务端这边返回的了。

3)客户端接收Binder。


@Override        public void onServiceConnected(ComponentName name, IBinder service) {            mService = new Messenger(service);            Log.i(TAG, "onServiceConnected()");        }

绑定成功接收返回的binder,看一下这个构造函数。

public Messenger(IBinder target) {        mTarget = IMessenger.Stub.asInterface(target);    }

和AIDL一模一样,将这个Ibinder接收过来只有装饰了起来。猜测,客户端发送时就是要用这个target装饰成的Proxy的send来转发到服务端了,看一下是不是这样。

3)客户端调用本地方法。

try {            if (mService != null) {                Message msg = Message.obtain(); //从消息池中取出最靠前的消息,如果没有消息就新建一个,然后重新赋值                msg.what = 1234;                msg.arg1 = 1;                msg.arg2 = 2;                msg.replyTo = mMessenger;                mService.send(msg);            }        } catch (RemoteException e) {            e.printStackTrace();        }

这里mService.send(msg),看一眼源码

    public void send(Message message) throws RemoteException {        mTarget.send(message);    }
果然是这个代理发送的。

4)服务端 由Binder来映射调用。还记得之前服务端的Messenger里的Handler里的Stub吗,再粘一遍,这里就调用自己发送sendMessenge了。

private final class MessengerImpl extends IMessenger.Stub {        public void send(Message msg) {            msg.sendingUid = Binder.getCallingUid();            Handler.this.sendMessage(msg);        }    }


这个服务端的Handler就可以接收到了,因为现在已经是本地发送与接收了。

5)服务端处理返回结果。

这里虽然不会挂起,但是也还是可以返回结果的,什么时候接收到就不一定了,Handler本就是这样。

服务端向客户端发送的代码

try {                Message toClient = Message.obtain();                toClient.what = 1234;                toClient.arg1 = fromClient.arg1 + 1;                toClient.arg2 = fromClient.arg2 + 1;                fromClient.replyTo.send(toClient);            } catch (RemoteException e) {                e.printStackTrace();            }

replyTo是客户端发过来的,这里的调用时调用的Messenger里的Handler里的sendMessage,客户端肯定是可以收到的,当然也是在底层转了一圈,但是在应用这边,可以理解为就是ClientActivity 中的 Handler。


6)客户端接收,本地Handler本地接收。没问题。

这就完成了一次通信,这种通信觉得好绕而且不同步,没用过,看到书上写的,就看了一下。


验证一下,看看从Service返回的值。是不是加了1

01-01 20:36:53.107 12387-12387/com.xue.qin.demo.message I/ClientActivity: Client Get Message :{ when=-1ms what=1234 arg1=2 arg2=3 target=com.xue.qin.demo.message.ClientActivity$1 }

OK






原创粉丝点击