文章标题

1 篇文章 0 订阅
1 篇文章 0 订阅

RabbitMQ topic主题的例子包含线程

==

我参考网上的资料做了两个接收者和一个生产者,总共有两个项目。接收者里指定要接收的信息:如1.#和2.#,生产者随意发送信息,只有1和2开头的路由器关键字会被接收其他的不行。

发往主题类型的转发器的消息不能随意的设置选择键(routing_key),必须是由点隔开的一系列的标识符组成。标识符可以是任何东西,但是一般都与消息的某些特性相关。绑定键和选择键的形式一样。主题类型的转发器背后的逻辑和直接类型的转发器很类似:一个附带特殊的选择键将会被转发到绑定键与之匹配的队列中。

RabbitMQ中消息传递模型的核心思想是:生产者不直接发送消息到队列。实际的运行环境中,生产者是不知道消息会发送到那个队列上,她只会将消息发送到一个交换器,交换器也像一个生产线,她一边接收生产者发来的消息,另外一边则根据交换规则,将消息放到队列中。交换器必须知道她所接收的消息是什么?它应该被放到那个队列中?它应该被添加到多个队列吗?还是应该丢弃?这些规则都是按照交换器的规则来确定的。

参考了以下两个例子:

http://blog.csdn.net/lmj623565791/article/details/37706355
https://www.cloudamqp.com/blog/2015-07-29-rabbitmq-on-android.html
https://github.com/cloudamqp/android-example

首先先看生产者的模块:

我们创建一个生产者线程。生产者仅能将消息发送到一个交易所。一个交易所是一个非常简单的事物。 在它的一遍,它从生产者那里接收消息,另一边将消息推送到队列中。 这个交换所必须清楚的知道它所接收到的消息要如何处理。是否将它附加到一个特别的队列中? 是否将它附加到多个队列中?或者是否它应该被丢弃。规则的定义是由交换类型决定的。

我们创建一个服务器的连接:这里我们连接到本地机器上的代理,因此它是localhost。如果我们想连接到不同机器上的代理,只需要说明它的主机名和IP地址。

    ConnectionFactory factory = new ConnectionFactory();
    private void setupConnectionFactory(){
        factory.setHost("localhost");
        factory.setPort(5672);
        factory.setUsername("test");
        factory.setPassword("test123");
    }

接着我们获取到连接connection 以及mq通道channel

Connection connection = factory.newConnection();
Channel channel = connection.createChannel();

RabbitMQ消息模型的核心理念是生产者永远不会直接发送任何消息给队列,一般的情况生产者甚至不知道消息应该发送到哪些队列。
相反的,生产者只能发送消息给转发器(Exchange)。转发器是非常简单的,一边接收从生产者发来的消息,另一边把消息推送到队列中。转发器必须清楚的知道消息如何处理它收到的每一条消息。是否应该追加到一个指定的队列?是否应该追加到多个队列?或者是否应该丢弃?这些规则通过转发器的类型进行定义。

接着创建一个这种类型的交易所exchange.我们必须声明一个发送队列,然后我们把消息发送到这个队列上这里是topic(主题)用来匹配的转发器类型

channel.exchangeDeclare(EXCHANGE_NAME,"topic");

既然有了转发器类型接下来就要输入信息还有转发器关键字了,因为消息内容message 是二进制数组,所以你可以随你喜好编码,队列通过路由关键字routing_key绑定。其中takeFirst检索并移除此队列的第一个元素,如果有必要,直到一个元素可用等。

String message = queue.takeFirst();
String routing_key = queue2.takeFirst();

然后开始发送信息,我们用下面的语句。其中第一个参数是交易所的名字。如果是空字符串说明它是默认的或者匿名的交易所:第二个路由关键字存在的话,消息通过路由关键字的名字路由到特定的队列上。如:(发送者1.abc接收者就要1.#)或者(两者一样发送者q接收者就q)。

channel.basicPublish(EXCHANGE_NAME,routing_key,null,message.getBytes());

这就是生产的部分,以下完整的生产者代码

package com.example.dong24;

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.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //服务器的连接:
        setupConnectionFactory();
        setupPubButton();

        //用于从线程中获取数据,更新ui
        final Handler incomingMessageHandler = new Handler(){
            @Override
            public void handleMessage(Message msg){
                String message = msg.getData().getString("msg");
                String message2 = msg.getData().getString("msg2");
                TextView tv = (TextView)findViewById(R.id.textView);
                TextView tv2 = (TextView)findViewById(R.id.textView2);
                Date now = new Date();
                SimpleDateFormat ft = new SimpleDateFormat("hh:mm:ss");
                tv.append(ft.format(now) + ' ' + message + "\n");
                tv2.append(ft.format(now) + ' ' +message2 + "\n");
                Log.i("test","msg  " + message);
            }
        };
        //开启发送消息的生产者线程
        publishToAMQP(incomingMessageHandler);
    }

    void setupPubButton(){
        Button button = (Button)findViewById(R.id.publish);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EditText et = (EditText)findViewById(R.id.text);
                publishMessage(et.getText().toString());
                et.setText("");
            }
        });
        Button button2 = (Button)findViewById(R.id.publish2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EditText et = (EditText)findViewById(R.id.text2);
                publishMessage2(et.getText().toString());
                et.setText("");
            }
        });
    }

    Thread publishThread;
    @Override
    protected void onDestroy(){
        super.onDestroy();
        publishThread.interrupt();
    }

    private BlockingDeque<String> queue = new LinkedBlockingDeque<String>();
    void publishMessage(String message){
        try{
            Log.d("","[q] " + message);
            //putLast在这个队列的末尾插入指定元素,如果空间成为提供必要的等待。
            queue.putLast(message);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    private  BlockingDeque<String> queue2 = new LinkedBlockingDeque<String>();
    void publishMessage2(String message) {
        try {
            Log.d("", "[q ] " + queue2);
            queue2.putLast(message);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 连接设置,我们创建一个服务器的连接:
     */
    //抽象的socket连接,注意协议版本的处理以及授权,诸如此类的事情。
    //这里我们连接到本地机器上的代理,因此它是localhost。如果我们想连接到不同机器上的代理,只需要说明它的主机名和IP地址。
    ConnectionFactory factory = new ConnectionFactory();
    private void setupConnectionFactory(){
        factory.setHost("192.168.X.XXX");//可以用自己的IP地址
        factory.setPort(5672);
        factory.setUsername("test");
        factory.setPassword("test123");
    }

    /**
     * 生产者线程
     */
    //  生产者仅能将消息发送到一个交易所。一个交易所是一个非常简单的事物。
    // 在它的一遍,它从生产者那里接收消息,另一边将消息推送到队列中。
    // 这个交换所必须清楚的知道它所接收到的消息要如何处理。是否将它附加到一个特别的队列中?
    // 是否将它附加到多个队列中?或者是否它应该被丢弃。规则的定义是由交换类型决定的。
     void publishToAMQP(final Handler handler){
        publishThread = new Thread(new Runnable() {
            private static final String EXCHANGE_NAME = "topic_logs";
            @Override
            public void run() {
                while(true){
                    try{
                        // 获取到连接以及mq通道
                        Connection connection = factory.newConnection();
                        Channel channel = connection.createChannel();
                        channel.confirmSelect();
                        //创建一个这种类型的交易所.我们必须声明一个发送队列,然后我们把消息发送到这个队列上
                        channel.exchangeDeclare(EXCHANGE_NAME,"topic");
                        while (true){
                            //输入关键字
                            // 声明一个队列是幂等的,仅仅在要声明的队列不存在时才创建。消息内容是二进制数组,所以你可以随你喜好编码。
                            //takeFirst检索并移除此队列的第一个元素,如果有必要,直到一个元素可用等。
                            String message = queue.takeFirst();
                            String routing_key = queue2.takeFirst();
                            try{
//这第一个参数是交易所的名字。空字符串说明它是默认的或者匿名的交易所:路由关键字存在的话,消息通过路由关键字的名字路由到特定的队列上。    
                                                channel.basicPublish(EXCHANGE_NAME,routing_key,null,message.getBytes());
System.out.println(" [x] Sent routingKey = " + routing_key + " ,msg = " + message + ".");

                                Log.d("","[s] "+message);
                                channel.waitForConfirmsOrDie();

                                //从message池中获取msg对象更高效
                                //对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用Message.obtain()这个静态的方法或者 Handler.obtainMessage()获取。
                                // Message.obtain()会从消息池中获取一个Message对象,如果消息池中是空的, 才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。
                                //并不需要担心消息池中的消息过多,它是有上限的,上限为10个。 Handler.obtainMessage()具有多个重载方法,如果查看源码,会发现其实Handler.obtainMessage()在内部也是 调用的Message.obtain()。
                                Message msg = handler.obtainMessage();
                                Message msg2 = handler.obtainMessage();
                                Bundle bundle = new Bundle();
                                bundle.putString("msg", message);
                                bundle.putString("msg2", routing_key);
                                msg.setData(bundle);
                                msg2.setData(bundle);
                                handler.sendMessage(msg);
                            }catch (Exception e){
                                Log.d("","[f] " + message);
                                //putFirst在这个队列的前面插入指定元素,如果空间成为提供必要的等待。
                                queue.putFirst(message);
                                queue2.putFirst(routing_key);
                                throw e;
                            }
                        }
                    }catch (InterruptedException e){
                        break;
                    }catch (Exception e){
                        Log.d("","Connection broken:" + e.getClass().getName());
                        try{
                            Thread.sleep(5000);
                        }catch (InterruptedException e1){
                            break;
                        }
                    }
                }
            }
        });
        publishThread.start();
    }

}

然后再看消费者的模块:

跟创建发送者相同,我们打开一个连接和一个通道,声明一个我们要消息的队列。注意要与发送的队列相匹配。

ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        factory.setPort(5672);
        factory.setUsername("test");
        factory.setPassword("test123");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();

接着声明转发器类型,我们把消息发送到这个队列上这里是topic(主题)用来匹配的转发器类型

channel.exchangeDeclare(EXCHANGE_NAME,"topic");

我们都为队列指定了一个特定的名称。能够为队列命名对我们来说是很关键的,我们需要指定消费者为某个队列。当我们希望在生产者和消费者间共享队列时,为队列命名是很重要的。
不过,对于我们的日志系统我们并不关心队列的名称。我们想要接收到所有的消息,而且我们也只对当前正在传递的数据的感兴趣。为了满足我们的需求,需要做两件事:第一, 无论什么时间连接到Rabbit我们都需要一个新的空的队列。为了实现,我们可以使用随机数创建队列,或者更好的,让服务器给我们提供一个随机的名称。第二, 一旦消费者与Rabbit断开,消费者所接收的那个队列应该被自动删除。Java中我们可以使用queueDeclare()方法,不传递任何参数,来创建一个非持久的、唯一的、自动删除的队列且队列名称由服务器随机产生。

我们再创建队列,队列名中包含一个随机队列名。使用无参数调queueDeclare()方法,我们创建一个自动产生的名字,不持久化,独占的,自动删除的队列。例如名字像amq.gen-JzTY20BRgKO-HjmUJj0wLg。

String queueName = channel.queueDeclare().getQueue();

然后输入信息还有转发器关键字了,队列通过路由关键字routing_key绑定。要与发送者的关键字保持一致。如:(发送者1.abc接收者就要1.#)或者(两者一样发送者q接收者就q)。其中takeFirst检索并移除此队列的第一个元素,如果有必要,直到一个元素可用等。

String routing_key = queue3.takeFirst();

之后是绑定,我们需要告诉交易所发送消息给我们的队列上。这交易所和队列之间的关系称之为一个绑定。接收所有routingKey相关的消息,将队列绑定到消息交换机exchange上。一个绑定是一个交换所和一个队列之间的关系。这个很容易理解为:这个队列是对这交易所的消息感兴趣。

绑定可以附带一个额外的参数routingKey。为了与避免basicPublish方法(发布消息的方法)的参数混淆,我们准备把它称作绑定键(binding key)。

 channel.queueBind(queueName,EXCHANGE_NAME,routing_key);

注意我们在这里同样声明了一个队列。以为我们可能在发送者之前启动接收者,在我们从中获取消息之前我们想要确定这队列是否真实存在。 我们通知服务器通过此队列给我们发送消息。因此服务器会异步的给我们推送消息,在这里我们提供一个回调对象用来缓存消息, 直到我们准备好再使用它们。这就是QueueingConsumer所做的事。

QueueingConsumer consumer = new QueueingConsumer(channel);

监听队列,自动返回完成 false手动

 channel.basicConsume(queueName,true,consumer);

最后获取消息,如果没有消息,这一步将会一直阻塞,开启nextDelivery阻塞方法(内部实现其实是阻塞队列的take方法)

QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
routing_key = delivery.getEnvelope().getRoutingKey();

这就是消费的部分,以下完整的消费者代码

package com.example.dong25;

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.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //服务器的连接:
        setupConnectionFactory();
        setupPubButton();

        //用于从线程中获取数据,更新ui
        final Handler incomingMessageHandler = new Handler(){
            @Override
            public void handleMessage(Message msg){
                String message3 = msg.getData().getString("msg3");
                String message4 = msg.getData().getString("msg4");
                TextView tv3 =(TextView)findViewById(R.id.textView3);
                TextView tv4 =(TextView)findViewById(R.id.textView4);
                Date now = new Date();
                SimpleDateFormat ft = new SimpleDateFormat("hh.mm.ss");
                tv3.append(ft.format(now) + ' ' + message3 + "\n");
                tv4.append(ft.format(now) + ' ' + message4 + "\n");
                Log.i("test","msg3  " + message3);
            }
        };
        //开启消费者线程   接收消息的消费者. 接收者将会输出从RabbitMQ中获取到来自发送者的消息。接收者会一直保持运行,等待消息
        subscribe(incomingMessageHandler);
        subscribe2(incomingMessageHandler);
    }

    void setupPubButton(){
        Button button3 = (Button)findViewById(R.id.publish3);
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EditText et = (EditText)findViewById(R.id.text3);
                publishMessage3(et.getText().toString());
                et.setText("");
            }
        });
        Button button4 = (Button)findViewById(R.id.publish4);
        button4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EditText et = (EditText)findViewById(R.id.text4);
                publishMessage4(et.getText().toString());
                et.setText("");
            }
        });
    }

    Thread subscribeThread;
    Thread subscribeThread2;
    @Override
    protected  void onDestroy(){
        super.onDestroy();
        subscribeThread.interrupt();
        subscribeThread2.interrupt();
    }

    private BlockingDeque<String> queue3 = new LinkedBlockingDeque<String>();
    void publishMessage3(String message){
        try{
            Log.d("","[q] " + message);
            //putLast在这个队列的末尾插入指定元素,如果空间成为提供必要的等待。
            queue3.putLast(message);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    private BlockingDeque<String> queue4 = new LinkedBlockingDeque<String>();
    void publishMessage4(String message){
        try{
            Log.d("","[q] " + message);
            queue4.putLast(message);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    /**
     * 连接设置,我们创建一个服务器的连接:
     */
    //抽象的socket连接,注意协议版本的处理以及授权,诸如此类的事情。
    //这里我们连接到本地机器上的代理,因此它是localhost。如果我们想连接到不同机器上的代理,只需要说明它的主机名和IP地址。
    ConnectionFactory factory = new ConnectionFactory();
    private void setupConnectionFactory(){
        factory.setHost("192.168.X.XXX");//可以用自己的IP地址
        factory.setPort(5672);
        factory.setUsername("test");
        factory.setPassword("test123");
    }

    /**
     * 消费者线程
     */
    //跟创建发送者相同,我们打开一个连接和一个通道,声明一个我们要消费的队列。注意要与发送的队列相匹配。
    void subscribe(final Handler handler){
        subscribeThread = new Thread(new Runnable() {
            private static final String EXCHANGE_NAME = "topic_logs";
            @Override
            public void run() {
                while (true){
                    try{
                        //创建一个连接   创建一个频道
                        Connection connection = factory.newConnection();
                        Channel channel = connection.createChannel();
                        //同一时刻服务器只会发一条消息给消费者 ,一次只发送一个,处理完成一个再获取下一个
                        channel.basicQos(1);
                        // 声明转发器
                        channel.exchangeDeclare(EXCHANGE_NAME,"topic");
                        // 队列名中包含一个随机队列名。使用无参数调用queueDeclare()方法,我们创建一个自动产生的名字,不持久化,独占的,自动删除的队列。
                        // 队列名中包含一个随机队列名。例如名字像amq.gen-JzTY20BRgKO-HjmUJj0wLg。
                        String queueName = channel.queueDeclare().getQueue();
                        //输入关键字
                        // 声明一个队列是幂等的,仅仅在要声明的队列不存在时才创建。消息内容是二进制数组,所以你可以随你喜好编码。
                        //takeFirst检索并移除此队列的第一个元素,如果有必要,直到一个元素可用等。
                        String routing_key = queue3.takeFirst();
                        //我们需要告诉交易所发送消息给我们的队列上。这交易所和队列之间的关系称之为一个绑定。
                        //接收所有routingKey相关的消息,将队列绑定到消息交换机exchange上
                        //一个绑定是一个交换所和一个队列之间的关系。这个很容易理解为:这个队列是对这交易所的消息感兴趣。
                        channel.queueBind(queueName,EXCHANGE_NAME,routing_key);
                        System.out.println(" [#] Waiting for messages about routingKey. To exit press CTRL+C");

                        //注意我们在这里同样声明了一个队列。以为我们可能在发送者之前启动接收者,在我们从中获取消息之前我们想要确定这队列是否真实存在。
                        // 我们通知服务器通过此队列给我们发送消息。因此服务器会异步的给我们推送消息,在这里我们提供一个回调对象用来缓存消息,
                        // 直到我们准备好再使用它们。这就是QueueingConsumer所做的事。
                        QueueingConsumer consumer = new QueueingConsumer(channel);
                        // 监听队列,自动返回完成  false手动
                        channel.basicConsume(queueName,true,consumer);
                        //循环获取消息
                        while(true){
                            //获取消息,如果没有消息,这一步将会一直阻塞,开启nextDelivery阻塞方法(内部实现其实是阻塞队列的take方法)
                            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
                            String message = new String(delivery.getBody());
                            routing_key = delivery.getEnvelope().getRoutingKey();
                            System.out.println(" [x] Received routingKey = " + routing_key + ",msg = " + message + ".");
                            Log.d("","[r] "+message);

                            //从message池中获取msg对象更高效
                            //对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用Message.obtain()这个静态的方法或者 Handler.obtainMessage()获取。
                            // Message.obtain()会从消息池中获取一个Message对象,如果消息池中是空的, 才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。
                            //并不需要担心消息池中的消息过多,它是有上限的,上限为10个。 Handler.obtainMessage()具有多个重载方法,如果查看源码,会发现其实Handler.obtainMessage()在内部也是 调用的Message.obtain()。
                            Message msg = handler.obtainMessage();
                            Bundle bundle = new Bundle();
                            bundle.putString("msg3",message);
                            msg.setData(bundle);
                            handler.sendMessage(msg);
                            //putFirst在这个队列的前面插入指定元素,如果空间成为提供必要的等待。
                            queue3.putFirst(routing_key);
                        }
                    }catch (InterruptedException e){
                        break;
                    }catch (Exception el){
                        Log.d("","Connection broken: "+ el.getClass().getName());
                        try{
                            Thread.sleep(4000);
                        }catch (InterruptedException e){
                            break;
                        }
                    }
                }
            }
        });
        subscribeThread.start();
    }

    /**
     * 消费者线程2 与1原理一样
     */
    void subscribe2(final Handler handler){
        subscribeThread2 = new Thread(new Runnable() {
            private static final String EXCHANGE_NAME = "topic_logs";
            @Override
            public void run() {
                while (true){
                    try{
                        Connection connection = factory.newConnection();
                        Channel channel = connection.createChannel();
                        channel.basicQos(1);
                        channel.exchangeDeclare(EXCHANGE_NAME,"topic");
                        String queueName = channel.queueDeclare().getQueue();

                        String routing_key2 = queue4.takeFirst();
                        channel.queueBind(queueName,EXCHANGE_NAME,routing_key2);
                        System.out.println(" [#] Waiting for messages about routingKey. To exit press CTRL+C");

                        QueueingConsumer consumer = new QueueingConsumer(channel);
                        channel.basicConsume(queueName,true,consumer);
                        while(true){
                            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
                            String message = new String(delivery.getBody());
                            routing_key2 = delivery.getEnvelope().getRoutingKey();
                            System.out.println(" [x] Received routingKey = " + routing_key2 + ",msg = " + message + ".");
                            Log.d("","[r] "+message);

                            Message msg2 = handler.obtainMessage();
                            Bundle bundle = new Bundle();
                            bundle.putString("msg4",message);
                            msg2.setData(bundle);
                            handler.sendMessage(msg2);
                            queue4.putFirst(routing_key2);
                        }
                    }catch (InterruptedException e){
                        break;
                    }catch (Exception el){
                        Log.d("","Connection broken: "+ el.getClass().getName());
                        try{
                            Thread.sleep(4000);
                        }catch (InterruptedException e){
                            break;
                        }
                    }
                }
            }
        });
        subscribeThread2.start();
    }
}

在页面方面的代码如下

这是生产者的页面

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin" >

    <TableLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:stretchColumns="1" >
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:layout_weight="1">
                <EditText
                    android:id="@+id/text2"
                    android:layout_width="fill_parent"
                    android:layout_height="50dp"
                    android:background="#ffffff"
                    android:hint="Enter a key"
                    android:layout_weight="1"/>
                <Button
                    android:id="@+id/publish2"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/text"
                    android:text="Publish routing_key"
                    android:layout_weight="1"/>
                <TextView
                    android:id="@+id/textView2"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/publish"
                    android:textColor="#000000"
                    android:layout_weight="1"/>
            </LinearLayout>

        </LinearLayout>

        <EditText
            android:id="@+id/text"
            android:layout_width="fill_parent"
            android:layout_height="50dp"
            android:background="#ffffff"
            android:hint="Enter a message" />
        <Button
            android:id="@+id/publish"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/text"
            android:text="Publish message" />
        <TextView
            android:id="@+id/textView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/publish"
            android:textColor="#000000" />

    </TableLayout>


</ScrollView>

这是消费者的页面

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin" >

    <TableLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:stretchColumns="1" >
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:layout_weight="1">
                <EditText
                    android:id="@+id/text3"
                    android:layout_width="fill_parent"
                    android:layout_height="50dp"
                    android:background="#ffffff"
                    android:hint="Receive a key"
                    android:layout_weight="1"/>
                <Button
                    android:id="@+id/publish3"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/text"
                    android:text="Receive routing_key"
                    android:layout_weight="1"/>
                <TextView
                    android:id="@+id/textView3"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/publish3"
                    android:textColor="#000000"
                    android:layout_weight="1"/>
            </LinearLayout>
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_weight="1">
            <EditText
                android:id="@+id/text4"
                android:layout_width="fill_parent"
                android:layout_height="50dp"
                android:background="#ffffff"
                android:hint="Receive a key"
                android:layout_weight="1"/>
            <Button
                android:id="@+id/publish4"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/text"
                android:text="Receive routing_key"
                android:layout_weight="1"/>
            <TextView
                android:id="@+id/textView4"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/publish3"
                android:textColor="#000000"
                android:layout_weight="1"/>
        </LinearLayout>
    </TableLayout>


</ScrollView>

代码的部分就结束了,注意是两个项目所以要两个MainActivity,当然你自己想要合并成一个也可以。我们还要

在AndroidManifest中加入

<uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="21" />

在build.gradle中加入—-内的内容

android {

----------

    packagingOptions {
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
    }

----------


    }
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.1.0'
    testCompile 'junit:junit:4.12'

----------

    compile 'com.rabbitmq:amqp-client:4.1.1'
    compile files('libs/junit.jar')
    compile files('libs/rabbitmq-client.jar')
    compile files('libs/commons-cli-1.1.jar')
    compile files('libs/commons-io-1.2.jar')
    compile files('libs/hamcrest-core.jar')
    compile files('libs/rabbitmq-client-tests.jar')

----------


}

以下就是源码
https://github.com/CHENRONG92/Dong23

效果如下:
模拟器的效果
run中发送和接收

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值