本次做的項目,有一部分是通過RabbitMQ來傳輸的實時數據。然後我這Android端就需要研究怎麼接收。以前用的volley什麼的,都是用http通訊的,這個稍微不太一樣,採用的消息隊列的方式,生產者與消費者的設計模式,觀察者模式。有次面試就掛這了TT。
看了下RabbitMQ,可以服務端上可以設置爲
-
工作隊列(Work queues)這種模式下,只有一個消息隊列,但是有多個消費者,這樣每個任務只會被一個消費者處理
-
訂閱發佈模式(Publish/Subscribe)這種模式下,會有多個隊列,每個隊列都有一個消費者
我們項目中服務端應該用的就是Publish/Subscribe這種。
從官網盜圖
除了生產者、消費者、消息隊列這些東西外,還多了一個X,這個X指的是Exchanges(可以翻譯成交換機)。
在這種模式下,生產者不直接把信息發送給消息隊列,而是隻發送給Exchanges,由Exchanges轉發給每個消息隊列。
Exchanges收到信息後會進行一些處理,比如這個消息我都應該發送給哪些隊列,還是隻發送給一個隊列,還是應該丟棄這個消息。這樣每個消息隊列從Exchanges收到的東西可能都不一樣,收到的消息都是根據每個消息隊列的需求定製的。比如我們項目分爲了油車和電車兩種,可以有兩個消息隊列,一個消息隊列只收油車數據,一個只收電車數據。這樣根據需要,我在客戶端這可以指定我只接受電車的數據了,我就可以從只收電車數據的這個消息隊列裏取了。
然後開始實現:
https://www.cloudamqp.com/blog/2015-07-29-rabbitmq-on-android.html
在這發現了一篇好教程,直接教我怎麼在Android上實現。
代碼不多,很容易就可以實現。
我把代碼精簡了下,因爲我這只需要從服務器接收數據就可以了,所以把publish的代碼刪了
主要流程如下:
- 設置連接參數setupConnectionFactory
- 創建一個用於從線程中接收數據來更新UI的handler
- 啓動一個訂閱者線程,創建一個隊列,將其bind到參數中指定的Exchanges上,並根據傳入的routingKey路由關鍵字來從Exchanges中接收指定類型的消息數據。
- 之後創建消費者consumer從消息隊列中循環請求數據。
package edu.hrbeu.ice.rabbitmqclient;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
public class MainActivity extends AppCompatActivity {
ConnectionFactory factory = new ConnectionFactory();
Thread subscribeThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//連接設置
setupConnectionFactory();
//用於從線程中獲取數據,更新ui
final Handler incomingMessageHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
String message = msg.getData().getString("msg");
TextView tv = (TextView) findViewById(R.id.textView);
Date now = new Date();
SimpleDateFormat ft = new SimpleDateFormat("hh:mm:ss");
tv.append(ft.format(now) + ' ' + message + '\n');
Log.i("test", "msg:" + message);
}
};
//開啓消費者線程
subscribe(incomingMessageHandler);
}
/**
* 連接設置
*/
private void setupConnectionFactory() {
factory.setHost("server url");
factory.setPort(5671);
factory.setUsername("guest");
factory.setPassword("guest");
}
/**
* 消費者線程
*/
void subscribe(final Handler handler) {
subscribeThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
//使用之前的設置,建立連接
Connection connection = factory.newConnection();
//創建一個通道
Channel channel = connection.createChannel();
//一次只發送一個,處理完成一個再獲取下一個
channel.basicQos(1);
AMQP.Queue.DeclareOk q = channel.queueDeclare();
//將隊列綁定到消息交換機exchange上
// queue exchange routingKey路由關鍵字,exchange根據這個關鍵字進行消息投遞。
channel.queueBind(q.getQueue(), "amq.fanout", "chat");
//創建消費者
QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(q.getQueue(), true, consumer);
while (true) {
//wait for the next message delivery and return it.
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
Log.d("", "[r] " + message);
//從message池中獲取msg對象更高效
Message msg = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString("msg", message);
msg.setData(bundle);
handler.sendMessage(msg);
}
} catch (InterruptedException e) {
break;
} catch (Exception e1) {
Log.d("", "Connection broken: " + e1.getClass().getName());
try {
Thread.sleep(5000); //sleep and then try again
} catch (InterruptedException e) {
break;
}
}
}
}
});
subscribeThread.start();
}
@Override
protected void onDestroy() {
super.onDestroy();
subscribeThread.interrupt();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129