使用Messenger

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a992036795/article/details/51593543

转载请注明出处: http://blog.csdn.net/a992036795/article/details/51593543

一、Messenger是android中一种轻量级的IPC方案,它的底层实现同aidl一样。
我们先来了解一下Messenger这个类,首先看一下Messenger的构造方法,它的主要有2个构造方法。

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

    /**
     * Create a Messenger from a raw IBinder, which had previously been
     * retrieved with {@link #getBinder}.
     * 
     * @param target The IBinder this Messenger should communicate with.
     */
    public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }

第一个构造方法,接受一个handle对象,然后使用 mTarget = target.getIMessenger(); 通过调用 Handler的getIMessenger方法返回一个实现了IMessenger接口的binder对象。为什么这样说呢? 我们参考一下Handle中 getIMessager方法就知道了。

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

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

可以看到,这和aidl是一样的,他返回了一个实现IMessenger接口的Binder对象那个。如果有framework 源码的话,还可以查看IMessenger.aidl文件
我这里给出IMessenger.aidl文件的内容:

package android.os;

import android.os.Message;

/** @hide */
oneway interface IMessenger {
    void send(in Message msg);
}

在来看第二个构造方法,第二个构造方法调用了 mTarget = IMessenger.Stub.asInterface(target);这里很明显看以看出跟aidl的使用一样,根据参数binder,获得了真正用来通信的那个binder对象,这个方法的返回有2中可能,一种是返回Stub,另一种返回 Proxy(夸进程时) 还记得吗?
可以参考我的上一篇博客:http://blog.csdn.net/a992036795/article/details/51579711
好了,原理大概就是这样。写的也比较粗略,请见谅。

二、使用。
讲完了原理,我们来看看如何使用它。我们新建一个SimpleService 类
重新onBind方法。

public class SimpleService extends Service {

    private static final String TAG = "SimpleService";

    static final int FIRST_RECEIVER_CODE = 0;

    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case FIRST_RECEIVER_CODE:
                    Log.i(TAG, "handleMessage: from client: " + msg.getData().getString("msg"));

                    break;
            }
        }
    };
    private Messenger mMessenger = new Messenger(mHandler);
  @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
}

可以看到,我们使用一个Handle 通过Messenger的第一个构造函数创建了一个Messenger用来和客户端通信,注意在onBind()方法中使用 mMessenger.getBinder()方法返回了底层用来通信的那个binder。
这里顺便给出getBinder()在Messenger类中的实现:

public IBinder getBinder() {
        return mTarget.asBinder();
    }

mTarget就是构造方法中赋值的那个binder.

这样我们在客户端进行bindService的时候就可以使用这个binder了。

   private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected: ");
            mServerMessenger = new Messenger(service);
            Message messager = Message.obtain();
            messager.what =SimpleService.FIRST_RECEIVER_CODE ;
            Bundle bundle = new Bundle();
            bundle.putString("msg","你好,我来自客户端");
             messager.setData(bundle);
            try {
                /*发送*/
                mServerMessenger.send(messager);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected: ");
        }
    } ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this,SimpleService.class);
        bindService(intent,conn,BIND_AUTO_CREATE) ;
    }

这里我们使用服务端传过来的 这个Binder 又重新构造出了一个Messenger类,用来和服务端通信,他们实际使用的是同一个binder对象。他们通过互相发送Message来相互通信。为什么可以使用Message呢?因为Message实现了Parcelable接口哈哈~

 */
public final class Message implements Parcelable {

    public int what;


    public int arg1; 


    public int arg2;


    public Object obj;

// 可以存放一个Messenger对象
    public Messenger replyTo;
    .....

}

另外,还可以看到Message中可以存放一个Messenger对象,那么我们就可以利用这个replayTo字段,使得客户端创建出来一个Messenger传递给服务端,然后服务端得到这个Messenger之后,来向客户端发消息。这就实现了双向通信。客户端创建Messenger的方法跟服务端创建Messenger一样,也使用一个Handler来完成,所以最终代码如下:
客户端:

 public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    static final int FIRST_RECEIVER_SERVER_CODE =1;

    /*Messenger 服务端*/
    private Messenger mServerMessenger  ;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case FIRST_RECEIVER_SERVER_CODE:
                    Log.i(TAG, "handleMessage: from server: "+msg.getData().getString("msg"));
                    break;
            }
        }
    } ;

    private Messenger mMessenger = new Messenger(mHandler);

    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected: ");
            mServerMessenger = new Messenger(service);
            Message messager = Message.obtain();
            messager.what =SimpleService.FIRST_RECEIVER_CODE ;
            Bundle bundle = new Bundle();
            bundle.putString("msg","你好,我来自客户端");
             messager.setData(bundle);
            /*将自己的Messenger传递给服务端*/
            messager.replyTo = mMessenger;
            try {
                /*发送*/
                mServerMessenger.send(messager);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected: ");
        }
    } ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this,SimpleService.class);
        bindService(intent,conn,BIND_AUTO_CREATE) ;
    }

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

服务端:

public class SimpleService extends Service {

    private static final String TAG = "SimpleService";

    static final int FIRST_RECEIVER_CODE = 0;

    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case FIRST_RECEIVER_CODE:
                    Log.i(TAG, "handleMessage: from client: " + msg.getData().getString("msg"));
                    clientMessenger = msg.replyTo;
                    Message messager = Message.obtain();
                    messager.what = MainActivity.FIRST_RECEIVER_SERVER_CODE;
                    Bundle bundle = new Bundle();
                    bundle.putString("msg","你好,我已经收到了你的Messenger.");
                    messager.setData(bundle);
                    try {
                        /*使用客户端传来的Messenger回复客户端*/
                        clientMessenger.send(messager);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }

                    break;
            }
        }
    };
    private Messenger mMessenger = new Messenger(mHandler);
    private Messenger clientMessenger;


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

最终 服务端先打印:

/com.blueberry.process1 I/SimpleService: handleMessage: from client: 你好,我来自客户端

然后客户端打印:

/com.blueberry.test05 I/MainActivity: handleMessage: from server: 你好,我已经收到了你的Messenger.

可以的看到这打印分别处于不同的进程,因为我使用了多进程。使得SimpleService发生在了另一个进程。

最后啰嗦一句:使得Service发生在别的进程的方法:在Manifest文件注册Service时添加一个生命 android:process=”com.blueberry.process1” 就可以使得它运行于一个名为com.blueberry.process1的进程中了。(默认进程名为包名)
也可是使用 android:process=”: remote”使用冒号,然后后面随便写个名字,那么这个进程名称将是” 包名:remote” 他将是名称为包名的那个进程的私有进程。
本次程序使用的方式为:

 <service android:name=".SimpleService"
            android:enabled="true"
            android:exported="true"
            android:process="com.blueberry.process1"
            ></service>
展开阅读全文

没有更多推荐了,返回首页