2024年最新Android 基于Message的进程间通信 Messenger完全解析(1),近期有面试的必看电影吗

最后

我见过很多技术leader在面试的时候,遇到处于迷茫期的大龄程序员,比面试官年龄都大。这些人有一些共同特征:可能工作了7、8年,还是每天重复给业务部门写代码,工作内容的重复性比较高,没有什么技术含量的工作。问到这些人的职业规划时,他们也没有太多想法。

其实30岁到40岁是一个人职业发展的黄金阶段,一定要在业务范围内的扩张,技术广度和深度提升上有自己的计划,才有助于在职业发展上有持续的发展路径,而不至于停滞不前。

不断奔跑,你就知道学习的意义所在!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

那么,什么叫基于消息的进程间通信方式呢?看个图理解下:

可以看到,我们可以在客户端发送一个Message给服务端,在服务端的handler中会接收到客户端的消息,然后进行对应的处理,处理完成后,再将结果等数据封装成Message,发送给客户端,客户端的handler中会接收到处理的结果。

这样的进程间通信是不是很爽呢?

  • 基于Message,相信大家都很熟悉

  • 支持回调的方式,也就是服务端处理完成长任务可以和客户端交互

  • 不需要编写aidl文件

此外,还支持,记录客户端对象的Messenger,然后可以实现一对多的通信;甚至作为一个转接处,任意两个进程都能通过服务端进行通信,这个后面再说。

看到这,有没有一些的小激动,我们可以不写aidl文件,方便的实现进程间通信了,是不是又可以装一下了。哈,下面看个简单的例子。


二、通信实例

这个例子,通过两个apk演示,一个apk是Server端,一个是Client端;

(1) Server端

代码

package com.imooc.messenger_server;

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;

public class MessengerService extends Service

{

private static final int MSG_SUM = 0x110;

//最好换成HandlerThread的形式

private Messenger mMessenger = new Messenger(new Handler()

{

@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();

}

}

服务端就一个Service,可以看到代码相当的简单,只需要去声明一个Messenger对象,然后onBind方法返回mMessenger.getBinder();

然后坐等客户端将消息发送到handleMessage想法,根据message.what去判断进行什么操作,然后做对应的操作,最终将结果通过 msgfromClient.replyTo.send(msgToClient);返回。

可以看到我们这里主要是取出客户端传来的两个数字,然后求和返回,这里我有意添加了sleep(2000)模拟耗时,注意在实际使用过程中,可以换成在独立开辟的线程中完成耗时操作,比如和HandlerThread结合使用。

注册文件

<service

android:name=“.MessengerService”

android:enabled=“true”

android:exported=“true”>

别忘了注册service,写完以后直接安装。

(二)客户端

Activity

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

}

}

代码也不复杂,首先bindService,然后在onServiceConnected中拿到回调的service(IBinder)对象,通过service对象去构造一个mService =new Messenger(service);然后就可以使用mService.send(msg)给服务端了。

我们消息的发送在Btn.onclick里面:

Message msgFromClient = Message.obtain(null, MSG_SUM, a, b);

msgFromClient.replyTo = mMessenger;

if (isConn)

{

//往服务端发送消息

mService.send(msgFromClient);

}

那么服务端会收到消息,处理完成会将结果返回,传到Client端的mMessenger中的Handler的handleMessage方法中。

布局文件

<LinearLayout android:id=“@+id/id_ll_container”

xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:orientation=“vertical”

android:paddingBottom=“@dimen/activity_vertical_margin”

android:paddingLeft=“@dimen/activity_horizontal_margin”

android:paddingRight=“@dimen/activity_horizontal_margin”

android:paddingTop=“@dimen/activity_vertical_margin”

tools:context=“.MainActivity”>

<TextView

android:id=“@+id/id_tv_callback”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:text=“Messenger Test!”/>

<Button android:id=“@+id/id_btn_add”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“add”/>

效果图

可以看到,我们每点击一次按钮,就往服务器发送个消息,服务器拿到消息执行完成后,将结果返回。

整个通信的代码看起来还是相当的清爽的,那么大家有没有对其内部的原理有一丝的好奇呢?下面我们就来看下其内部是如何实现的。

对了,源码分析前,这里插一句,大家通过代码可以看到服务端往客户端传递数据是通过msg.replyTo这个对象的。那么服务端完全可以做到,使用一个List甚至Map去存储所有绑定的客户端的msg.replyTo对象,然后想给谁发消息都可以。甚至可以把A进程发来的消息,通过B进程的msg.replyTo发到B进程那里去。相关代码呢,可以参考官方的文档:service,注意下拉找:Remote Messenger Service Sample。


三、源码分析

其实Messenger的内部实现的,实际上也是依赖于aidl文件实现的。

(一)首先我们看客户端向服务端通信

服务端

服务端的onBind是这么写的:

public IBinder onBind(Intent intent)

{

return mMessenger.getBinder();

}

那么点进去:

最后

以前一直是自己在网上东平西凑的找,找到的东西也是零零散散,很多时候都是看着看着就没了,时间浪费了,问题却还没得到解决,很让人抓狂。

后面我就自己整理了一套资料,还别说,真香!

资料有条理,有系统,还很全面,我不方便直接放出来,大家可以先看看有没有用得到的地方吧。

系列教程图片

2020Android复习资料汇总.png

flutter

NDK

设计思想开源框架

微信小程序

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

();

}

那么点进去:

最后

以前一直是自己在网上东平西凑的找,找到的东西也是零零散散,很多时候都是看着看着就没了,时间浪费了,问题却还没得到解决,很让人抓狂。

后面我就自己整理了一套资料,还别说,真香!

资料有条理,有系统,还很全面,我不方便直接放出来,大家可以先看看有没有用得到的地方吧。

[外链图片转存中…(img-t9IZISvL-1715134636032)]

[外链图片转存中…(img-gtrukgtc-1715134636033)]

[外链图片转存中…(img-oevPXNbH-1715134636033)]

[外链图片转存中…(img-pcsc1yUQ-1715134636033)]

[外链图片转存中…(img-5CLmH54U-1715134636034)]

[外链图片转存中…(img-Puu7hqia-1715134636034)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 30
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值