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);
}
}
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