进程间通信----Messenger

在上次,我写到了利用aidl来进行进程间通信的方式,并且满足了基本需求,然后,使用aidl方式进行进程间通信始终比较麻烦,需要写aidl文件等等,那么是否有比较简单的通信方式呢,是有的那就是Messenger

本篇的内容主要是参考着

http://blog.csdn.net/lmj623565791/article/details/47017485; 
【张鸿洋的博客】

来完成的,我只是在看了之后进行了自己的编写测试,并且针对我在项目中需要传递自定义对象扩展了一下


使用Messenger进行通信的方式要比aidl写起来方便的多,这种方式大概的流程为:



这种方式可以做到双向通信


那么下面就是代码了,首先是服务端:我自己的测试的项目在另一台电脑上,所以就拿借鉴的博主的代码来了,其实

我自己写的是差不多的

package com.example.aidlClientdemo;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;

public class ProcessCommonicationService extends Service{
	private static final int MSG_SUM = 0x110;
	
	HandlerThread handlerThread = new HandlerThread("myHandlerThread");       

	//这里在handler构造器内传入handlerThread的Lopper,可以让handleMessage在handlerThread的线程内队列执行
    private Messenger mMessenger = new Messenger(new Handler(handlerThread.getLooper())
    {
        @Override
        public void handleMessage(Message msgfromClient)
        {
            Message msgToClient = Message.obtain(msgfromClient);//返回给客户端的消息
            switch (msgfromClient.what)
            {
                //msg 客户端传来的消息
                case MSG_SUM:
                    msgToClient.what = MSG_SUM;
                    try
                    {
                        //模拟耗时
                        Thread.sleep(2000);
                        msgToClient.arg2 = msgfromClient.arg1 + msgfromClient.arg2;
                        msgfromClient.replyTo.send(msgToClient);
                    } catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    } catch (RemoteException e)
                    {
                        e.printStackTrace();
                    }
                    break;
            }

            super.handleMessage(msgfromClient);
        }
    });
    
    @Override
	public void onCreate() {
		super.onCreate();
		//使用handlerThread可以进行队列执行
		handlerThread.start();
	}

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

客户端代码结束之后就是服务端的代码

package com.imooc.messenger_client;

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.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity
{
    private static final String TAG = "MainActivity";
    private static final int MSG_SUM = 0x110;

    private Button mBtnAdd;
    private LinearLayout mLyContainer;
    //显示连接状态
    private TextView mTvState;

    private Messenger mService;
    private boolean isConn;


    private Messenger mMessenger = new Messenger(new Handler()
    {
        @Override
        public void handleMessage(Message msgFromServer)
        {
            switch (msgFromServer.what)
            {
                case MSG_SUM:
                    TextView tv = (TextView) mLyContainer.findViewById(msgFromServer.arg1);
                    tv.setText(tv.getText() + "=>" + msgFromServer.arg2);
                    break;
            }
            super.handleMessage(msgFromServer);
        }
    });


    private ServiceConnection mConn = new ServiceConnection()
    {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            mService = new Messenger(service);
            isConn = true;
            mTvState.setText("connected!");
        }

        @Override
        public void onServiceDisconnected(ComponentName name)
        {
            mService = null;
            isConn = false;
            mTvState.setText("disconnected!");
        }
    };

    private int mA;

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

        //开始绑定服务
        bindServiceInvoked();

        mTvState = (TextView) findViewById(R.id.id_tv_callback);
        mBtnAdd = (Button) findViewById(R.id.id_btn_add);
        mLyContainer = (LinearLayout) findViewById(R.id.id_ll_container);

        mBtnAdd.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                try
                {
                    int a = mA++;
                    int b = (int) (Math.random() * 100);

                    //创建一个tv,添加到LinearLayout中
                    TextView tv = new TextView(MainActivity.this);
                    tv.setText(a + " + " + b + " = caculating ...");
                    tv.setId(a);
                    mLyContainer.addView(tv);

                    Message msgFromClient = Message.obtain(null, MSG_SUM, a, b);
                    msgFromClient.replyTo = mMessenger;
                    if (isConn)
                    {
                        //往服务端发送消息
                        mService.send(msgFromClient);
                    }
                } catch (RemoteException e)
                {
                    e.printStackTrace();
                }
            }
        });

    }

    private void bindServiceInvoked()
    {
        Intent intent = new Intent();
        intent.setAction("com.zhy.aidl.calc");
        bindService(intent, mConn, Context.BIND_AUTO_CREATE);
        Log.e(TAG, "bindService invoked !");
    }

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


}


在上面的例子中,是传递了基本类型的参数,而我们实际使用中则很多都会需要用到传递自定义类型,这种时候只需要这么做就行了

Message msgFromClient = Message.obtain(null, MSG_SUM, a, b);
        msgFromClient.replyTo = mMessenger;
        Bundle bundle = new Bundle();
        bundle.putParcelable("data", new User());
        msgFromClient.setData(bundle);
        
        if (isConn)
        {
            //往服务端发送消息
            mService.send(msgFromClient);
        }
就是通过在Message中添加Bundle来传递我们自定义的对象,这个对象需要实现Parcelable接口


通过上面的方式可以方便的进行进程间的通讯


那么,为什么通过这种方式可以进行进程间通讯呢?这一点在我解读的文章中也有描述


之前我了解过aidl的进程通讯方式,在aidl的通讯方式可以发现与这里非常相似


1、bindService的方式

2、ServiceConnection的使用

3、aidl接口的对象获取,其实可以发现这里也是一样的

这里调用的通讯方式为Messenger mService = new Messenger(service);

而aidl的接口对象获取方式为:ICalcAIDL mCalcAidl = ICalcAIDL.Stub.asInterface(service);

表面上看起来好像有点不同,但是,如果我们去看Messenger的构造器

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


这里返回的mTarget对象为

private final IMessenger mTarget;

跟aidl客户端的方式一模一样,在调用通讯方法send(Message message)我们再去看

public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }
很明显,其实内部的逻辑方式就是使用的aidl



那么客户端我们发现了是一样的,再去看服务端呢?

在服务端我们的代码是

    private Messenger mMessenger = new Messenger(new Handler(handlerThread.getLooper())
    {
        @Override
        public void handleMessage(Message msgfromClient)
        {
            Message msgToClient = Message.obtain(msgfromClient);//返回给客户端的消息
            switch (msgfromClient.what)
            {
                //msg 客户端传来的消息
                case MSG_SUM:
                    msgToClient.what = MSG_SUM;
                    try
                    {
                        //模拟耗时
                        Thread.sleep(2000);
                        msgToClient.arg2 = msgfromClient.arg1 + msgfromClient.arg2;
                        msgfromClient.replyTo.send(msgToClient);
                    } catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    } catch (RemoteException e)
                    {
                        e.printStackTrace();
                    }
                    break;
            }

            super.handleMessage(msgfromClient);
        }
    });
然后是

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


而aidl的通讯方式是

private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub()  
    {  
  
        @Override  
        public int add(int x, int y) throws RemoteException  
        {  
            return x + y;  
        }  
  
        @Override  
        public int min(int x, int y) throws RemoteException  
        {  
            return x - y;  
        }  
  
    };  

然后

    public IBinder onBind(Intent t)  
    {  
        Log.e(TAG, "onBind");  
        return mBinder;  
    }  
就是将一个实现了我们自定义的aidl对象的Stub接口的对象作为通讯方式返回


那么,现在的Messenger方式又是怎样的呢

我们首先来看Messenger的构造器,来看看这这里面做了什么

 public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }
这里从我们传入的handler中取出了IMessenger对象


这个IMessenger,其实是依赖一个aidl生成的类

于:frameworks/base/core/java/android/os/IMessenger.aidl.

package android.os;  

import android.os.Message;  

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

这样,在服务端就只差一个东西了,就是实现了 IMessenger.Stub的对象,这个对象我们去哪里找?

然后我们去看

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

这里的target.getMessenger()方法,我们进去看一下,可以看到

    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);
        }
    }
找到了!这个MessengerImpl对象就是实现了IMessenger.Stub的对象


这样一来,需要的要素就都齐了,按照现在的代码来推测的话,不难推测出

    @Override
    public IBinder onBind(Intent intent)
    {
        return mMessenger.getBinder();
    }
这里返回的mMessenger.getBinder()应该是 MessengerImpl对象,不过我们还是得去确认一下


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

这里调用了asBinder()方法,再进去看

@Override public android.os.IBinder asBinder()
{
return this;
}
可以看到,asBinder方法就是返回的mTarget对象自己,就是 MessengerImpl对象


这里这个asBinder方法的源码是aidl文件在gen路径下生成的类里面可以看到的,如果读者想看的话,可以在aidl的例子中查看,就可以看到


那么Messenger配合Handler的进程间通信的原理到这里就分析结束了,从这个看来的话,其实我们完全也可以自己写一个类似于Messenger的对象用来进行进程间通信,并且利用Message可以传递数据的特性来进行数据的传递,可以说还是非常方便的
















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值