最近在做关于Android端从ActiveMQ中取数据的应用。如果ActiveMQ中有数据,就往Android端推送。
1.ActiveMQ和MQTT
ActiveMQ 是 Apache 出品,最流行的,强有力的开源消息总线。MQ英文名MessageQueue,中文名也就是大家用的消息队列,说白了就是一个消息的接受和转发的容器,可用于消息推送。ActiveMQ 是一个完全支持 JMS1.1 和 J2EE 1.4 规范的 JMS Provider实现,尽管JMS 规范出台已经很久的事情了,但是 JMS 在当今的J2EE 应用中间仍然扮演着特殊的地位。支持Java,C,C ++,C#,Ruby,Perl,Python,PHP等各种跨语言客户端和协议。MQTT v3.1对ActiveMQ也是支持的。
那什么是MQTT?MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和制动器(比如通过Twitter让房屋联网)的通信协议。Mqtt各个平台下用到的包还有例子。接下来我主要介绍的是Android平台的MQTT的使用。
2.fusesource和paho
看了网上的许多介绍,大多数都用的是这个两个基于MQTT协议实现的jar。fusesource和paho这两个项目我最开始用的是fusesource,因为网上好多都说这个简单易用而paho用起来复杂一些。但是,我用之后发现我跳入了fusesource的大坑里。我当时用的Android 4.4的系统,内存时1G(没办法,客户就提供这个系统)。虽然客观条件艰苦,但也没有必要运行项目一段时间后就报OOM的错。当时数据量(图片的URL)还是挺大的,1秒大概可以推送20条数据的量。错误大概是这个样的:
java.lang.OutOfMemoryError
at org.fusesource.hawtdispatch.util.BufferPool.create(BufferPool.java:35)
at org.fusesource.hawtdispatch.util.BufferPool.create(BufferPool.java:25)
at org.fusesource.hawtdispatch.util.ThreadLocalPool.checkout(ThreadLocalPool.java:78)
at org.fusesource.hawtdispatch.transport.AbstractProtocolCodec.allocateNextWriteBuffer(AbstractProtocolCodec.java:153)
at org.fusesource.hawtdispatch.transport.AbstractProtocolCodec.flushNextWriteBuffer(AbstractProtocolCodec.java:186)
at org.fusesource.hawtdispatch.transport.AbstractProtocolCodec.flush(AbstractProtocolCodec.java:229)
at org.fusesource.hawtdispatch.transport.TcpTransport.flush(TcpTransport.java:678)
at org.fusesource.hawtdispatch.transport.TcpTransport$5.run(TcpTransport.java:579)
at org.fusesource.hawtdispatch.internal.HawtCustomDispatchSource$1.run(HawtCustomDispatchSource.java:127)
at org.fusesource.hawtdispatch.internal.SerialDispatchQueue.run(SerialDispatchQueue.java:100)
at org.fusesource.hawtdispatch.internal.pool.SimpleThread.run(SimpleThread.java:77)
我开始一直以为是我自己写的代码问题而导致的这个问题,我是千方百计的优化,费尽心力的google,最终也是无济于事。好吧,我放弃了,小伙伴们要是知道这个问题怎么解决,给我留下言啊。然后我就投入到paho的怀抱中了。接下来,让我们瞅一瞅怎么入门吧!
3.paho的配置
3.1 build.gradle
compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
3.2 AndroidManifest.xml
权限:
<!-- 使用paho必须要使用的3个权限,sPermissions the Application Requires -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 访问网络 -->
<uses-permission android:name="android.permission.INTERNET" />
service:
<!-- Mqtt Service -->
<service android:name="org.eclipse.paho.android.service.MqttService">
</service>
3.3 Activity
String serverUri = "tcp://***.***.**.***:1883";
MqttAndroidClient mqttAndroidClient;
String clientId = "pahoAndroidClient";
//订阅的主题
String [] topics = new String[]{"ActiveMQ/Metadata","ActiveMQ/Mdblk"};
public void initMQTT(){
clientId = clientId + System.currentTimeMillis();
mqttAndroidClient = new MqttAndroidClient(getApplicationContext(),serverUri,clientId);
mqttAndroidClient.setCallback(new MqttCallbackExtended() {
@Override
public void connectComplete(boolean reconnect, String serverURI) {
Log.i("paho","connectComplete reconnect:"+reconnect);
Log.i("paho","connectComplete serverURI:"+serverURI);
if (reconnect) {
// Because Clean Session is true, we need to re-subscribe
subscribeToTopic();
} else {
Log.i("paho","connectComplete 没有重新连接");
}
Toast.makeText(MainActivity.this,"connectComplete",Toast.LENGTH_SHORT).show();
}
@Override
public void connectionLost(Throwable cause) {
Log.i("paho","The Connection was lost.:"+cause);
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
System.out.println("Incoming message: " + topic + " : " + new String(message.getPayload()));
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
}
});
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setAutomaticReconnect(true);
mqttConnectOptions.setCleanSession(false);
try {
mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
DisconnectedBufferOptions disconnectedBufferOptions = new DisconnectedBufferOptions();
disconnectedBufferOptions.setBufferEnabled(true);
disconnectedBufferOptions.setBufferSize(100);
disconnectedBufferOptions.setPersistBuffer(false);
disconnectedBufferOptions.setDeleteOldestMessages(false);
mqttAndroidClient.setBufferOpts(disconnectedBufferOptions);
subscribeToTopic();
Toast.makeText(MainActivity.this,"onSuccess",Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.i("paho","Failed to connect to:" + serverUri);
Toast.makeText(MainActivity.this,"onFailure",Toast.LENGTH_SHORT).show();
}
});
} catch (MqttException ex){
ex.printStackTrace();
}
}
public void subscribeToTopic(){
try {
mqttAndroidClient.subscribe(topics, new int[]{0,0}, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.i("paho","Subscribed");
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
}
});
mqttAndroidClient.subscribe(topics, new int[]{0,0},new IMqttMessageListener[]{
new IMqttMessageListener() {//抓拍
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
//在这里处理接收到第一个订阅主题的消息
System.out.println("抓拍 Message: " + topic + " : " + new String(message.getPayload()));
}
},
new IMqttMessageListener() {//比对成功
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
//在这里处理接收到第二个订阅主题的消息
System.out.println("比对成功 Message: " + topic + " : " + new String(message.getPayload()));
}
}
});
} catch (MqttException ex){
System.err.println("Exception whilst subscribing");
ex.printStackTrace();
}
}
4.总结
如果你需要做Android消息推送的话,你可以继续研究paho里面的例子。我只是抛砖引玉:
MQTT和ActiveMQ
MQTT协议中文版
深入浅出JMS(二)–ActiveMQ简单介绍以及安装