android通信,android通信框架
Android跨进程通信
Android 为我们提供了以下几种进程通信机制(供开发者使用的进程通信 API)对应的文章链接如下:
我们注重客户提出的每个要求,我们充分考虑每一个细节,我们积极的做好网站设计制作、成都网站制作服务,我们努力开拓更好的视野,通过不懈的努力,创新互联公司赢得了业内的良好声誉,这一切,也不断的激励着我们更好的服务客户。 主要业务:网站建设,网站制作,网站设计,微信小程序定制开发,网站开发,技术开发实力,DIV+CSS,PHP及ASP,ASP.Net,SQL数据库的技术开发工程师。
Android 进阶:进程通信之 Binder 机制浅析
Android 进阶:进程通信之 AIDL 解析
Android MQTT 通信
MQTT 协议 是基于发布/订阅模式的物联网通信协议,凭借简单易实现、支持 QoS、报文小等特点,占据了物联网协议的半壁江山。
常用于 IOT 物联网和一些需要服务端主动通知客户端的场景。
1. 导入依赖
2. 创建 MqttHelper 辅助类,设置回调监听
3. 连接 MQTT
连接成功或失败,以及中途的连接掉线,会触发 OnMqttStatusChangeListener 回调
4. MQTT 连接状态监听
5. MQTT 收发消息监听
onSubMessage 订阅的消息回调,因为存在订阅多个 topic 的情况,所以回调能知道是来自哪个 Topic 的消息;
onPubMessage 发布的消息回调,用于确认发布的消息是否发送成功。
6. MQTT 订阅 Topic
需要在 MQTT 连接成功后才能订阅 topic,否则订阅 Topic 不成功,收不到对应消息
7. MQTT 取消订阅 Topic
8. MQTT 发布消息
9. MQTT 断开连接
10. 通知设置
由于 MQTT 启动了一个 Service,而 Android 8.0 以上对于后台 Service 限制时长 5 秒;所以将 MqttService 绑定到 Notification 上成为了一个前台通知;通知的标题和内容显示可以在 strings.xml 中设置,对应属性如下:
Android 8.0 及以上开启前台服务绑定到通知,8.0 以下默认不启用,可将 mqtt_foreground_notification_low_26 设为 true,将 8.0 以下设备也开启前台通知服务
创建 MQTT 实例时需要传送参数 MqttOptions,下面将介绍下部分参数;
1. Topic
MQTT 是一种发布/订阅的消息协议, 通过设定的主题 Topic,
发布者向 Topic 发送的 payload 负载消息会经过服务器, 转发到所有订阅
该 Topic 的订阅者
通配符 : 假想移动端消息推送场景,有的系统消息是全体用户接收,有的消息是 Android 或 iOS 设备接收, 又或者是某些消息具体推送到用户,当然, 对应的多种类型消息可以通过多订阅几个对应的 Topic 解决,也可以使用通配符;
通配符有两个, " + " 和 " # ", 与正斜杠 " / " 组合使用;加号只能表示一级Topic, 井号可以表示任意层级 Topic; 例如: 订阅 Topic为 " System/+ ", 发布者发布的 Topic 可以是 System、System/Android、System/iOS; 但是不能是 System/iOS/123, 而订阅的 Topic 如果是" System/# " 则可以收到;
注意,只有订阅的 Topic 才可以使用 通配符, 发布和遗嘱的 Topic 不能包含通配符.
2. ClientID
发布者和订阅者都是属于客户端, 客户端与服务端建立连接之后,发送的第一个报文消息必须是 Connect 消息,而 Connect 的消息载荷中必须包含 clientID 客户端唯一标识;
如果两个客户端的 clientID 一样, 则服务端记录第一个客户端连接之后再收到第二个客户端连接请求,则会向一个客户端发送 Disconnect 报文断开连接, 并连接第二个客户端, 而如果此时设置了自动重连, 第一个客户端再次连接,服务端又断开与第二个的连接, 连上第一个客户端, 如此将导致两个客户端不断的被挤掉重连.
注意: clientID 使用的字符最好是 大小写字母和数字, 长度最好限制在[1, 23] 之间;
3. 遗嘱消息
可选参数, 客户端没有主动向服务端发起 disconnect 断开连接消息,然而服务端检测到和客户端之间的连接已断开, 此时服务端将该客户端设置的遗嘱消息发送出去
应用场景: 客户端因网络等情况掉线之后, 可以及时通知到所有订阅该遗嘱 Topic 的客户端;
遗嘱 Topic 中不能存在通配符.
4. Session
客户端和服务端之间建立的会话状态, 一般用于消息保存, 如果设置清除 Session,则每次客户端和服务端建立连接会创建一个新的会话,之前连接中的消息不能恢复,
而设置不清除会话, 对应发布者发送的 qos 为 1和2 的消息,还未被订阅者接收确认,则需要保存在会话中, 以便订阅者下次连接可以恢复这些消息;
注意: Session 存储的消息是保存在内容中的, 所以如果不是重要的消息,最好是设置清除 Session, 或者设置 qos = 0;
5. 心跳包
标识客户端传输一次控制报文到下一次传输之间允许的空闲时间;在这段时间内,如果客户端没有其他任何报文发送,必须发送一个 PINGREQ 报文到服务器,而如果服务端在 1.5 倍心跳时间内没有收到客户端消息,则会主动断开客户端的连接,发送其遗嘱消息给所有订阅者。而服务端收到 PINGREQ 报文之后,立即返回 PINGRESP 报文给客户端
心跳时间单位为秒,占用2个字节,最大 2^16 - 1 = 65535秒(18小时12分钟15秒),设置为 0 表示不使用心跳机制; 心跳时间一般设置为几分钟或几十秒即可,时间短点可以更快的发出遗嘱消息通知掉线,但是时间短会增加消息频率,影响服务端并发; 微信长连接为 300 秒,而三大运营商貌似也有个连接时间最小的为 5 分钟。
6. qos
服务质量等级 qos 对应两部分,一是客户端到服务端发送的消息, 一是服务端到客户端订阅的消息; 从发布者到订阅者实际 qos 为两段路中 qos 最小的。
qos 可选值 0(最多交付一次)、1(最少交付一次)、2(正好交付一次);
qos = 0 :接收方不发送响应,发送方不进行重试;发送方只管发一次,不管是否发成功,也不管接收方是否成功接收,适用于不重要的数据传输;
qos = 1 :确保消息至少有一次到达接收方,发送方向接收方发送消息,需要等待接收方返回应答消息,如果发送方在一定时间之内没有收到应答,发送方继续下一次消息发送,直到收到应答消息,删除本地消息缓存,不再发送;所以接收方可能收到1-n次消息;适用于需要收到所有消息,客户端可以处理重复消息。
qos = 2 :确保消息只一次到达接收方,发送方和接收方之间消息处理流程最复杂;
Mqtt Qos 深度解读 和 MQTT协议QoS2 准确一次送达的实现
7. payload 负载消息
字节流类型, 是 MQTT 通信传输的真实数据
8. 保留消息
发布消息时设置, 对应参数 retain, 服务端将保留对应 Topic 最新的一条消息记录; 保留消息的作用是每次客户端连接上线都会收到其 Topic 的最后一条保留消息, 所以可能存在网络不稳定,频繁掉线重连,每次重连重复收到保留消息;
可以向对应的 Topic 发送一条 空消息,用于清除保留消息。
MQTT 服务搭建 Apache Apollo 服务器 搭建 MQTT 服务
Github 仓库
mqtt 协议
了解Android进程间通信的四种方式
由于应用程序之间不能共享内存。在不同应用程序之间交互数据(跨进程通讯),在android
SDK中提供了4种用于跨进程通讯的方式。这4种方式正好对应于android系统中4种应用程序组
件:Activity、Content Provider、Broadcast和Service。其中Activity可以跨进程调用其他应
用程序的Activity;Content Provider可以跨进程访问其他应用程序中的数据(以Cursor对象形
式返回),当然,也可以对其他应用程序的数据进行增、删、改操 作;Broadcast可以向
android系统中所有应用程序发送广播,而需要跨进程通讯的应用程序可以监听这些广播;
Service和Content Provider类似,也可以访问其他应用程序中的数据,但不同的是,Content
Provider返回的是Cursor对象,而Service返回的是Java对象,这种可以跨进程通讯的服务叫
AIDL服务。
Android进程间和线程间通信方式
进程:是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
线程:是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一些在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
区别:
(1)、一个程序至少有一个进程,一个进程至少有一个线程;
(2)、线程的划分尺度小于进程,使得多线程程序的并发性高;
(3)、进程在执行过程中拥有独立的内存单元,而多个线程共享内存,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉。
---------------------
一、Android进程间通信方式
1.Bundle
由于Activity,Service,Receiver都是可以通过Intent来携带Bundle传输数据的,所以我们可以在一个进程中通过Intent将携带数据的Bundle发送到另一个进程的组件。
缺点:无法传输Bundle不支持的数据类型。
2.ContentProvider
ContentProvider是Android四大组件之一,以表格的方式来储存数据,提供给外界,即Content Provider可以跨进程访问其他应用程序中的数据。用法是继承ContentProvider,实现onCreate,query,update,insert,delete和getType方法,onCreate是负责创建时做一些初始化的工作,增删查改的方法就是对数据的查询和修改,getType是返回一个String,表示Uri请求的类型。注册完后就可以使用ContentResolver去请求指定的Uri。
3.文件
两个进程可以到同一个文件去交换数据,我们不仅可以保存文本文件,还可以将对象持久化到文件,从另一个文件恢复。要注意的是,当并发读/写时可能会出现并发的问题。
4.Broadcast
Broadcast可以向android系统中所有应用程序发送广播,而需要跨进程通讯的应用程序可以监听这些广播。
5.AIDL方式
Service和Content Provider类似,也可以访问其他应用程序中的数据,Content Provider返回的是Cursor对象,而Service返回的是Java对象,这种可以跨进程通讯的服务叫AIDL服务。
AIDL通过定义服务端暴露的接口,以提供给客户端来调用,AIDL使服务器可以并行处理,而Messenger封装了AIDL之后只能串行运行,所以Messenger一般用作消息传递。
6.Messenger
Messenger是基于AIDL实现的,服务端(被动方)提供一个Service来处理客户端(主动方)连接,维护一个Handler来创建Messenger,在onBind时返回Messenger的binder。
双方用Messenger来发送数据,用Handler来处理数据。Messenger处理数据依靠Handler,所以是串行的,也就是说,Handler接到多个message时,就要排队依次处理。
7.Socket
Socket方法是通过网络来进行数据交换,注意的是要在子线程请求,不然会堵塞主线程。客户端和服务端建立连接之后即可不断传输数据,比较适合实时的数据传输
二、Android线程间通信方式
一般说线程间通信主要是指主线程(也叫UI线程)和子线程之间的通信,主要有以下两种方式:
1.AsyncTask机制
AsyncTask,异步任务,也就是说在UI线程运行的时候,可以在后台的执行一些异步的操作;AsyncTask可以很容易且正确地使用UI线程,AsyncTask允许进行后台操作,并在不显示使用工作线程或Handler机制的情况下,将结果反馈给UI线程。但是AsyncTask只能用于短时间的操作(最多几秒就应该结束的操作),如果需要长时间运行在后台,就不适合使用AsyncTask了,只能去使用Java提供的其他API来实现。
2.Handler机制
Handler,继承自Object类,用来发送和处理Message对象或Runnable对象;Handler在创建时会与当前所在的线程的Looper对象相关联(如果当前线程的Looper为空或不存在,则会抛出异常,此时需要在线程中主动调用Looper.prepare()来创建一个Looper对象)。使用Handler的主要作用就是在后面的过程中发送和处理Message对象和让其他的线程完成某一个动作(如在工作线程中通过Handler对象发送一个Message对象,让UI线程进行UI的更新,然后UI线程就会在MessageQueue中得到这个Message对象(取出Message对象是由其相关联的Looper对象完成的),并作出相应的响应)。
三、Android两个子线程之间通信
面试的过程中,有些面试官可能会问Android子线程之间的通信方式,由于绝大部分程序员主要关注的是Android主线程和子线程之间的通信,所以这个问题很容易让人懵逼。
主线程和子线程之间的通信可以通过主线程中的handler把子线程中的message发给主线程中的looper,或者,主线程中的handler通过post向looper中发送一个runnable。但looper默认存在于main线程中,子线程中没有Looper,该怎么办呢?其实原理很简单,把looper绑定到子线程中,并且创建一个handler。在另一个线程中通过这个handler发送消息,就可以实现子线程之间的通信了。
子线程创建handler的两种方式:
方式一:给子线程创建Looper对象:
new Thread(new Runnable() {
public void run() {
Looper.prepare(); // 给这个Thread创建Looper对象,一个Thead只有一个Looper对象
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
Looper.loop(); // 不断遍历MessageQueue中是否有消息
};
}).start();
---------------------
方式二:获取主线程的looper,或者说是UI线程的looper:
new Thread(new Runnable() {
public void run() {
Handler handler = new Handler(Looper.getMainLooper()){ // 区别在这!!!
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
};
}).start();
---------------------
网站栏目:android通信,android通信框架
浏览路径:http://azwzsj.com/article/dsdiejh.html