本次做的项目,有一部分是通过RabbitMQ来传输的实时数据。然后我这Android端就需要研究怎么接收。以前用的volley什么的,都是用http通讯的,这个稍微不太一样,采用的消息队列的方式,生产者与消费者的设计模式,观察者模式。有次面试就挂这了TT。

看了下RabbitMQ,可以服务端上可以设置为

工作队列(Work queues)这种模式下,只有一个消息队列,但是有多个消费者,这样每个任务只会被一个消费者处理

订阅发布模式(Publish/Subscribe)这种模式下,会有多个队列,每个队列都有一个消费者

我们项目中服务端应该用的就是Publish/Subscribe这种。 
RabbitMQ的Android端接收 
从官网盗图

除了生产者、消费者、消息队列这些东西外,还多了一个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();
    }

}