IPC之Messenger

我们知道Service开启的方式有俩种:
- startService
- bindService
使用startService开启服务, 一般都不和Service进行交互,
而使用bindService开启服务,一般都需要和Service进行交互,因此,如果想获取Service,并和它进行交互,请使用bindService
使用bindService有如下几种情况
-1,service和client都属于同一个process
-2, service和client属于不同的process, 给service发送消息
-3, service和client属于不同的process, 需要调用service(其实是onBind()方法返回的ibinder对象)的多个方法

第一种方式,很简单,直接创建一个内部类继承自Binder, 然后在service的onBind()方法中返回此内部类的对象
第二种方式,我们可以使用Messenger的getBinder()对象作为onBind的返回值。
第三种方式,是采取aidl方式进行通信。

今天,我们只说第二种,分析第二种的原理:
首先,创建一个service,并且在AndroidManifest.xml里面配置,并加上android:process属性

public class MessagerService extends Service {
    public MessagerService() {
    }
    //创建一个handler
    private Handler ipcHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.e("LF", "msg.what : " + msg.what + ", msg.arg1 : " + msg.arg1);
            Log.e("LF", "handleMessage thread : " + Thread.currentThread() + ", process : " + Process.myPid());
        }
    };
    //使用ipcHandler构建一个Messenger对象
    private Messenger messenger = new Messenger(ipcHandler);

    @Override
    public IBinder onBind(Intent intent) {
        Log.e("LF", "onBind pid : " + Process.myPid());
        //将messenger中的binder返回。
        return messenger.getBinder();
    }
}
//在manifest中的配置, 加上process属性,就表示运行在不同的进程中
        <service
            android:name=".MessagerService"
            android:process=".remoteMessenger"
            android:enabled="true"
            android:exported="true">
        </service>

首先来看一下Messenger messenger = new Messenger(ipcHandler); 打开Messenger的源码,通过handler构造一个Messenger, 内部只是调用handler的getIMessenger()方法,将其返回值保存在mTarget成员变量。

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

在来看一下onBind()方法中返回的messenger.getBinder()方法在Messenger类中的定义

    public IBinder getBinder() {
        //它返回的是mTarget.asBinder对象
        return mTarget.asBinder();
    }

通过前面构造Messenger时,我们清楚mTarget是Handler中的getIMessenger()的返回值, 我们来看一下此方法

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

从方法的定义可以看到getIMessenger()方法返回的是MessengerImpl对象,

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

MessengerImpl类是Handler类的内部类,它继承自IMessenger.Stub类,看到Stub,我们是不是想到了AIDL文件自动生成的内部类呀,Stub类是继承自Binder的,所以MessengerImpl是一个Binder对象。

我们也来看一下此IMessenger.java类

public interface IMessenger extends android.os.IInterface
{

    public static abstract class Stub extends android.os.Binder implements android.os.IMessenger {
        ......
        public Stub()
        {
            this.attachInterface(this, DESCRIPTOR);
        }

        public static android.os.IMessenger asInterface(android.os.IBinder obj) {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof android.os.IMessenger))) {
                return ((android.os.IMessenger)iin);
}
            return new android.os.IMessenger.Stub.Proxy(obj);
        }
        @Override public android.os.IBinder asBinder() {
            return this;
        }
    ......

和我们自己创建的aidl文件之后,系统给我们自动生成的一模一样, 因此我们在onBind()方法中返回的mTarget.asBinder() ,就等于handler.getIMessenger().asBinder() ,最后其实就是MessengerImpl, 它是Stub的子类。和我们自己创建aidl一样, 至此,服务端的代码分析完了, 我们接下来看一下客户端。

客户端的调用, 和正常的bindService一样,采取显示intent的方式,(android 5.0以上必须采取显示intent的方式开启服务, 否则会抛异常)

private Messenger mMessenger;
    ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.e("LF", " iBinder : " + iBinder);
            //根据iBinder创建一个Messenger对象
            mMessenger = new Messenger(iBinder);
            isConnection = true;
            try {
                iBinder.linkToDeath(new MyDeathRecipient(), 0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
        }
    };
//开启服务的代码
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            //开启服务端的代码
            case R.id.bindMessager:
                Intent messagerIntent = new Intent(this, MessagerService.class);
                this.bindService(messagerIntent, conn, BIND_AUTO_CREATE);
                break;
            case R.id.unBindMessager:
                //unbind service的代码
                if (isConnection) {
                    this.unbindService(conn);
                    isConnection = false;
                }
                break;
            case R.id.invokeIPC:
                //调用服务端的代码
                if (isConnection && mMessenger != null) {
                    Message message = Message.obtain();
                    message.what = 10;
                    message.arg1 = 21;
                    try {
                        mMessenger.send(message);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
                break;
            default:

        }
    }

当服务开启之后,我们在onServiceConnected()方法中可以获取到service端返回的iBinder对象。此iBinder对象在非IPC中,它就是MessengerImpl对象,如果在IPC中,那么此iBinder是BinderProxy, 它是一个代理。

        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.e("LF", " iBinder : " + iBinder);
            mMessenger = new Messenger(iBinder);
            isConnection = true;
            try {
                iBinder.linkToDeath(new MyDeathRecipient(), 0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

我们来看一下new Messenger(iBinder) 这句话,底层做了啥?

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

从上述代码里面可以很清楚的看到,其实它就是我们之前使用aidl的写法,将IMessenger.Stub.asInterface返回的对象,赋值给mTarget对象
来看一下IMessenger.Stub 中asInterface()方法的定义

public static android.os.IMessenger asInterface(android.os.IBinder obj) {
    if ((obj==null)) {
        return null;
    }
    //首先在本地找,如果找到,就直接返回
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof android.os.IMessenger))) {
        return ((android.os.IMessenger)iin);
    }
    //本地没有,就返回Stub.Proxy内部类对象
    return new android.os.IMessenger.Stub.Proxy(obj);
}

这里我们先不分析asInterface底层实现,只需要记住,如果是IPC,客户端获取到的是proxy.所以,这里mTarget是IMessenger.Stub的内部proxy
我们再来看一下mMessenger.send(message);这句底层实现

    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }

其实就是调用mTarget的send。也就是调用proxy的send

@Override public void send(android.os.Message msg) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
try {
    _data.writeInterfaceToken(DESCRIPTOR);
if ((msg!=null)) {
    _data.writeInt(1);
    msg.writeToParcel(_data, 0);
} else {
    _data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_send, _data, null, android.os.IBinder.FLAG_ONEWAY);
} finally {
    _data.recycle();
}
}
static final int TRANSACTION_send = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);

我们看到是调用mRemote的transact方法,mRemote对象是我们传入的iBinder对象,其实最终会调用Stub的onTransact方法, 然后在onTransact方法里面进行switch根据传入的TRANSACTION_send 判断,最后调用的是MessengerImpl的send方法

        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }

最终就会走正常的handler 的流程。

从以上的分析,可以看出,Messenger底层也是使用AIDL来实现的。在服务端通过Handler来构建一个MessengerImpl 的Bindler对象,将此Bindler对象通过onBind()方法返回, 在客户端,以bindService开启服务之后, 根据服务端传回来的iBinder对象创建一个Messenger对象, 这样客户端中的Messenger对象,就获取到了service端的IMessenger的代理(IPC, 非IPC是MessengerImpl对象)。这样,客户端和服务端,就可以通过Messenger的send方法进行通信了。

当然使用Messenger也可以从client端向service端的子线程发送handler消息, 只需要在service端构建Messenger的时候,传入一个带子线程Looper对象的Handler即可。

public class MessagerService extends Service {
    public MessagerService() {
    }

    private Handler ipcHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.e("LF", "msg.what : " + msg.what + ", msg.arg1 : " + msg.arg1);
            Log.e("LF", "handleMessage thread : " + Thread.currentThread() + ", process : " + Process.myPid());
        }
    };
    private  class MyAsyncHandler extends  Handler {
        MyAsyncHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.e("LF", "msg.what : " + msg.what + ", msg.arg1 : " + msg.arg1);
            Log.e("LF", "handleMessage thread : " + Thread.currentThread() + ", process : " + Process.myPid());
        }
    }

    private Looper mHandlerLooper;
    private  MyAsyncHandler myAsyncHandler;
    private  Messenger mAsyncMessenger;

    @Override
    public void onCreate() {
        super.onCreate();
        //构建一个HandlerThread ,HandlerThread内部开启一个子线程,并且创建一个Looper,并进行loop循环。
        HandlerThread handlerThread = new HandlerThread("MessengerHandlerThread");
        handlerThread.start();
        this.mHandlerLooper = handlerThread.getLooper();
        this.myAsyncHandler = new MyAsyncHandler(mHandlerLooper);
        //根据此Handler去构建一个Messenger对象
        mAsyncMessenger = new Messenger(myAsyncHandler);
    }

    private Messenger messenger = new Messenger(ipcHandler);

    @Override
    public IBinder onBind(Intent intent) {
        return  mAsyncMessenger.getBinder();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        this.mHandlerLooper.quit();//自己开启的loop一定要记得退出
    }
}

唯一注意一点的是,自己创建的Looper一定要记得调用quit或者quitSafe退出,否则,线程会一直存在。

如果服务端需要给客户端回应,那么在client端也构建一个Messenger对象,将Messenger对象赋值给message的replyTo,发送给service端,

Messenger 的内部是使用handler来处理消息的,所以,它是一个串行的过程。如果要处理并发的请求,或者跨进程调用service端的方法,请使用AIDL

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值