由于直播项目的推流SDK,拉流SDK已经稳定。所以这段时间一直开发业务层新需求。业务层的核心灵魂就是层层的消息传递,今天就来总结一下andorid的应用层的各种消息传递。

1.线程间通讯 ——— Handler,HandlerThread等。
2.组件间通信 ——— BroadcastReceiver,接口回调等。
3. 第三方通信 ——— EventBus,rxBus
4.进程间通信 ——— Content Provider ,Broadcast ,AIDL等。
5.长连接推送 ——— WebSocket,XMPP等。

1.线程间通讯

Handler
一个Android应用程序被创建的时候都会创建一个UI主线程,但是有时我们会有一些比较耗时的操作,为了防止阻塞UI主线程,我们会将耗时的操作放到子线程中进行处理,处理完之后操作UI,但是Android不允许子线程操作UI,违背了Android单线程模型的原则(即 Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行),所以Android通过Handler消息机制来实现线程之间的通讯。

Handler机制主要角色

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。 Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。 MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。 Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。 Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

Handler机制主要运用

sendEmptyMessage(int);//发送一个空的消息
sendMessage(Message);//发送消息,消息中可以携带参数
sendMessageAtTime(Message, long);//未来某一时间点发送消息
sendMessageDelayed(Message, long);//延时Nms发送消息post(Runnable);//提交计划任务马上执行
postAtTime(Runnable, long);//提交计划任务在未来的时间点执行
postDelayed(Runnable, long);//提交计划任务延时Nms执行

主线程定义Handler

 Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case 0://完成主界面更新,拿到数据String data = (String) msg.obj;textView.setText(data);break;default:break;}}};

子线程执行耗时操作然后发消息,通知Handler完成UI更新

private void getDataFromNet() {new Thread(new Runnable() {@Overridepublic void run() {//需要数据传递,用下面方法;Message msg = new Message();msg.obj = "网络数据";//可以是基本类型,可以是对象,可以是List、map等;mHandler.sendMessage(msg);}}).start();}

Handler机制扩展:

Activity.runOnUiThread(Runnable)
View.post(Runnable)
以上也可以从子线程切换到主线程。

HandlerThread:
HandlerThread本质上就是一个普通Thread,只不过内部建立了Looper.

HandlerThread用法实例

 //创建一个线程,线程名字:handler-threadmyHandlerThread = new HandlerThread( "handler-thread") ;//开启一个线程myHandlerThread.start();//在这个线程中创建一个handler对象 主要这个handler是在子线程中循环接受消息的handler = new Handler( myHandlerThread.getLooper() ){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);//这个方法是运行在 handler-thread 线程中的 ,可以执行耗时操作Log.d( "handler " , "消息: " + msg.what + "  线程: " +                Thread.currentThread().getName()  ) ;}};//在主线程给handler发送消息handler.sendEmptyMessage( 1 ) ;new Thread(new Runnable() {@Overridepublic void run() {//在子线程给handler发送数据handler.sendEmptyMessage( 2 ) ;}}).start() ;}@Overrideprotected void onDestroy() {super.onDestroy();//释放资源myHandlerThread.quit() ;}

Looper的quit方法或quitSafely方法
相同点:
将不在接受新的事件加入消息队列。

不同点
当我们调用Looper的quit方法时,实际上执行了MessageQueue中的removeAllMessagesLocked方法,该方法的作用是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送的需要延迟执行的消息)还是非延迟消息。

当我们调用Looper的quitSafely方法时,实际上执行了MessageQueue中的removeAllFutureMessagesLocked方法,通过名字就可以看出,该方法只会清空MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理,quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息。

无论是调用了quit方法还是quitSafely方法只会,Looper就不再接收新的消息。即在调用了Looper的quit或quitSafely方法之后,消息循环就终结了,这时候再通过Handler调用sendMessage或post等方法发送消息时均返回false,表示消息没有成功放入消息队列MessageQueue中,因为消息队列已经退出了。

需要注意的是Looper的quit方法从API Level 1就存在了,但是Looper的quitSafely方法从API Level 18才添加进来。

我在直播推流中应用了HandlerThread,每编码组装出来一帧视频就发送一个handler消息,然后HandlerThread线程接收消息数据并用libRtmp推倒服务器。此时可以监控队列中有多少消息在循环,可以监听进出队列的比例,如果超出一定的范围说明网络不好,需要执行丢帧策略。

2.组件间通信

BroadcastReceiver与接口回调 是 EventBus,rxBus没出现之前的主要组件间通信方式。

BroadcastReceiver广播就不在介绍了, 广播传递本身是有安全隐患的,需要设置权限,每一个Activity都要定义、注册,解注册广播无形中加大了工作量和维护成本。已经不适应用在组件间通信。

接口回调: 和观察者模式大致一样。
实例:

public class DataSynManager {private LinkedList<IDataSynListener> autoListeners = new LinkedList();//监听集合private static DataSynManager mInstance;//单例引用/*** 获取单例引用** @return*/public static DataSynManager getInstance() {if (mInstance == null) {synchronized (DataSynManager.class) {if (mInstance == null) {mInstance = new DataSynManager();}}}return mInstance;}/*** 添加同步数据监听*/public void registerDataSynListener(IDataSynListener autoDataListener) {if (autoListeners == null) {autoListeners = new LinkedList<IDataSynListener>();}if (!autoListeners.contains(autoDataListener)) {autoListeners.add(autoDataListener);}}/*** 移除同步数据监听*/public void unRegisterDataSynListener(IDataSynListener autoDataListener) {if (autoListeners == null) {return;}if (autoListeners.contains(autoDataListener)) {autoListeners.remove(autoDataListener);}}/*** 执行数据同步** @param count*/public void doDataSyn(final int count) {if (autoListeners == null) {autoListeners = new LinkedList();}new Handler().post(new Runnable() {@Overridepublic void run() {for (IDataSynListener dataSynListener : autoListeners) {dataSynListener.onDataSyn(count);}}});}/*** 清除所有监听者*/public void release() {if (autoListeners != null) {autoListeners.clear();autoListeners = null;}}public interface IDataSynListener {void onDataSyn(int count);}
}

使用:

//添加监听DataSynManager.getInstance().registerDataSynListener(dataSynListener);
//移除监听
DataSynManager.getInstance().unRegisterDataSynListener(dataSynListener//个监听);DataSynManager.IDataSynListener dataSynListener=new DataSynManager.IDataSynListener() {@Overridepublic void onDataSyn(int count) {//接下来执行同步操作}}};
//发送事件
DataSynManager.getInstance().doDa(5);

3. 第三方通信

EventBus主要角色:

 Event 传递的事件对象Subscriber  事件的订阅者 Publisher  事件的发布者ThreadMode 定义函数在何种线程中执行

定义一个事件类型

public class DataEvent {private int count;public int getCount() {return count;}public void setCount(int count) {this.count = count;}
}
//订阅EventBus.getDefault().register(this);//订阅//解除订阅EventBus.getDefault().unregister(this);//解除订阅//发布事件EventBus.getDefault().post(new DataEvent());//订阅事件处理@Subscribe(threadMode = ThreadMode.MAIN) //在ui线程执行public void onDataEvent(DataEvent event) {Log.e(TAG, "event---->" + event.getCount());}

ThreadMode总共四个:

NAIN UI主线程
BACKGROUND 后台线程
POSTING 和发布者处在同一个线程
ASYNC 异步线程

事件的优先级类似广播的优先级,优先级越高优先获得消息

 @Subscribe(threadMode = ThreadMode.MAIN,priority = 100) //在ui线程执行 优先级100public void onDataEvent(DataEvent event) {Log.e(TAG, "event---->" + event.getCount());}

终止事件往下传递
发送有序广播可以终止广播的继续往下传递,EventBus也实现了此功能

 EventBus.getDefault().cancelEventDelivery(event) ;//优先级高的订阅者可以终止事件往下传递

EventBus黏性事件
何为黏性事件呢?简单讲,就是在发送事件之后再订阅该事件也能收到该事件,跟黏性广播类似。

本身粘性广播用的就比较少,为了方便理解成订阅在发布事件之后,但同样可以收到事件。订阅/解除订阅和普通事件一样,但是处理订阅函数有所不同,需要注解中添加sticky = true

  @Subscribe(threadMode = ThreadMode.MAIN,sticky = true) //在ui线程执行public void onDataEvent(DataEvent event) {Log.e(TAG, "event---->" + event.getCount());}//发送粘性事件EventBus.getDefault().postSticky(new DataEvent());//对于粘性广播我们都比较清楚属于常驻广播,对于EventBus粘性事件也类似,我们如果不再需要该粘性事件我们可以移除EventBus.getDefault().removeStickyEvent(new DataEvent());//或者调用移除所有粘性事件EventBus.getDefault().removeAllStickyEvents();

RXBus:如果项目中用了rxjava的话可以参考https://github.com/AndroidKnife/RxBus 自己封装一个。

4.进程间通信

Content Provider
Android应用程序可以使用文件或SqlLite数据库来存储数据。Content Provider提供了一种在多个应用程序之间数据共享的方式(跨进程共享数据)。应用程序可以利用Content Provider完成下面的工作
1. 查询数据
2. 修改数据
3. 添加数据
4. 删除数据
虽然Content Provider也可以在同一个应用程序中被访问,但这么做并没有什么意义。Content Provider存在的目的向其他应用程序共享数据和允许其他应用程序对数据进行增、删、改操作。
Android系统本身提供了很多Content Provider,例如,音频、视频、联系人信息等等。我们可以通过这些Content Provider获得相关信息的列表。这些列表数据将以Cursor对象返回。因此,从Content Provider返回的数据是二维表的形式。
广播(Broadcast)
广播是一种被动跨进程通讯的方式。当某个程序向系统发送广播时,其他的应用程序只能被动地接收广播数据。这就象电台进行广播一样,听众只能被动地收听,而不能主动与电台进行沟通。
在应用程序中发送广播比较简单。只需要调用sendBroadcast方法即可。该方法需要一个Intent对象。通过Intent对象可以发送需要广播的数据。
AIDL Service
这是我个人比较推崇的方式,因为它相比Broadcast而言,虽然实现上稍微麻烦了一点,但是它的优势就是不会像广播那样在手机中的广播较多时会有明显的时延,甚至有广播发送不成功的情况出现。
注意普通的Service并不能实现跨进程操作,实际上普通的Service和它所在的应用处于同一个进程中,而且它也不会专门开一条新的线程,因此如果在普通的Service中实现在耗时的任务,需要新开线程。
要实现跨进程通信,需要借助AIDL(Android Interface Definition Language)。Android中的跨进程服务其实是采用C/S的架构,因而AIDL的目的就是实现通信接口。

AIDL具体使用可参考http://www.jianshu.com/p/d1fac6ccee98

5.长连接推送

Websocket
支持客户端和服务器端的双向通信,而且协议的头部又没有HTTP的Header那么大,于是,Websocket就诞生了!

Websocket是应用层第七层上的一个应用层协议,它必须依赖 HTTP 协议进行一次握手 ,握手成功后,数据就直接从 TCP 通道传输,与 HTTP 无关了。

Websocket的数据传输是frame形式传输的,比如会将一条消息分为几个frame,按照先后顺序传输出去。这样做会有几个好处:

1 大数据的传输可以分片传输,不用考虑到数据大小导致的长度标志位不足够的情况。

2 和http的chunk一样,可以边生成数据边传递消息,即提高传输效率。

XMPP中定义了三个角色,客户端,服务器,网关。通信能够在这三者的任意两个之间双向发生。服务器同时承担了客户端信息记录,连接管理和信息的路由功能。网关承担着与异构即时通信系统的互联互通,异构系统可以包括SMS(短信),MSN,ICQ等。基本的网络形式是单客户端通过TCP/IP连接到单服务器,然后在之上传输XML。

QQ是使用类似XMPP协议的UDP协议进行发送和接收消息的。当你的机器安装了QQ以后,实际上,你既是服务端(Server),又是客户端(Client)。当你登录QQ时,你的QQ作为Client连接到腾讯公司的主服务器上,当你看谁在线时,你的QQ又一次作为Client从QQ Server上读取在线网友名单。当你和你的QQ伙伴进行聊天时,如果你和对方的连接比较稳定,你和他的聊天内容都是以UDP的形式,在计算机之间传 送。如果你和对方的连接不是很稳定,QQ服务器将为你们的聊天内容进行中转。其他的即时通信软件原理与此大同小异。

所以基于WebSocke和XMPP都可以开发出IM社交聊天类的app

Android消息传递机制总结相关推荐

  1. android串口补位,Rust多线程中的消息传递机制

    代码说话. use std::thread; use std::sync::mpsc; use std::time::Duration; fn main() { let (tx, rx) = mpsc ...

  2. Android Handler消息传递机制

    Android中只允许UI线程(也就是主线程)修改Activity里的UI组件.实际开发中,新启动的线程需要周期性地改变界面组件的属性值就需要借助Handler的消息传递机制. Handler类 Ha ...

  3. 【Android开发】线程与消息处理-Handler消息传递机制之Looper

    在前面已经介绍了在Android中如何创建.开启.休眠和中断线程.不过,此时并没有在新创建的子线程中对UI界面上的内容进行操作,如果应用前面介绍的方法对UI界面进行操作,将抛出异常. 为此,Andro ...

  4. android handler 传递对象,Android之Handler消息传递机制详解

    前言 在Android开发中,多线程应用是非常频繁的,其中Handler机制随处可见. 下面就本人对Handle的一些理解与大家一起分享,共同回顾下Handle异步消息传递机制. 1.Handler是 ...

  5. android handler的机制和原理_一文搞懂handler:彻底明白Android消息机制的原理及源码

    提起Android消息机制,想必都不陌生.其中包含三个部分:Handler,MessageQueue以及Looper,三者共同协作,完成消息机制的运行.本篇文章将由浅入深解析Android消息机制的运 ...

  6. Android消息处理机制

    Google参考了Windows的消息处理机制,在Android系统中实现了一套类似的消息处理机制.学习Android的消息处理机制,有几个概念(类)必须了解: 1.       Message 消息 ...

  7. 我理解的Hanlder--android消息传递机制

    每一个学习Android的同学都会觉得Handler是一个神奇的东西,我也一样,开始我以为我懂了Handler的机制,后来发现自己是一知半解,昨天想想,我能否自己实现一个Handler,让子线程与Ac ...

  8. Android消息传递之EventBus 3.0使用详解

    前言: 前面两篇不仅学习了子线程与UI主线程之间的通信方式,也学习了如何实现组件之间通信,基于前面的知识我们今天来分析一下EventBus是如何管理事件总线的,EventBus到底是不是最佳方案?学习 ...

  9. 理解 Android 消息机制

    本人只是Android小菜一个,写技术文章只是为了总结自己最近学习到的知识,从来不敢为人师,如果里面有不正确的地方请大家尽情指出,谢谢! 本文基于原生 Android 9.0 源码来解析 Androi ...

最新文章

  1. 备忘:C语言void *
  2. 修改react-native项目名称
  3. switch-case和if-else可互换时
  4. 2路由策略_route-map(执行路由策略)
  5. ajax jq 图片上传请求头_Jquery ajaxsubmit上传图片实现代码
  6. zabbix3.0.4监控mysql主从同步
  7. java字符串连接效率_关于java:字符串连接中的“+”是否会影响效率?
  8. 线性回归(五)---弹性网络回归
  9. 学javascript看什么书?
  10. deepnode处理过的图片_微信图文排版用什么软件?文章图片大小不一样排版不齐怎么办?...
  11. 直播疑难杂症排查(1)— 播放失败
  12. linux的前端环境搭建-安装配置git客户端与github连接
  13. Java 设计模式 之 单例模式(Singleton)
  14. CSS —— 多媒体查询
  15. matplotlib.colors(ListedColormap)
  16. ios修改apn的插件_iPhone手机APN修改方案
  17. android从相册或拍照获取照片第三方开源库TakePhoto
  18. caffe配置 一生不可自决
  19. MindMapper中如何添加父主题
  20. 从零开始perp交叉编译及配置

热门文章

  1. 0 基础 Java 自学之路(2022年最新版)
  2. 【机器学习】一文读懂正则化与LASSO回归,Ridge回归
  3. BATCH/批处理命令
  4. FreeType 用法
  5. 【管理心得之八】通过现象看本质,小王和小张谁更胜任?
  6. facebook下载
  7. 数学建模暑期集训26:遗传算法
  8. (深度学习快速入门)第三章第一节:多层感知器简介
  9. bat批处理笔记(一)
  10. 线性规划(matlab篇)