精华内容
下载资源
问答
  • 逻辑上,可以看成是一并发的Exclusive Consumer。JMS消息属性JMXGroupID被用来区分Message Group。Message Groups特性保证所有具有相同JMSGroupID的消息会被分发到相同的Consumer(只要这个Consumer保持Active)。...

    1 消息分组

    1.1 概述

    从Apache官方文档的话说,是Exclusive Consumer功能的增强。逻辑上,可以看成是一种并发的Exclusive Consumer。JMS消息属性JMXGroupID被用来区分Message Group。Message Groups特性保证所有具有相同JMSGroupID的消息会被分发到相同的Consumer(只要这个Consumer保持Active)。另一方面,Message Groups也是一种负载均衡的机制。
    在一个消息被分发到Consumer前,Broker会检查消息的JMSGroupID属性。如果存在,那么broker会检查是否有某个Consumer拥有这个Message Group。如果没有,那么broker会选择一个Consumer,并将它关联到这个Message Group。此后,这个Consumer会接收这个Message Group的所有消息。直到Consumer被关闭。
    Message Group被关闭。通过发送一个消息,并设置这个消息的JMSXGroupSeq为-1.
    从4.1版本开始,ActiveMQ支持一个布尔字段JMSXGroupFirstForConsumer 。当某个message group的第一个消息被发送到consumer的时候,这个字段被设置。如果客户使用failover transport连接到broker。在由于网络问题等造成客户重新连接到broker的时候,相同message group的消息可能会被分发到不同与之前的consumer,因此JMSXGroupFirstForConsumer字段也会被重新设置。

    1.2 测试代码

    1.2.1 生产者发送消息

    public class OrderProcedure {
    
        public static void main(String[] args) throws JMSException, InterruptedException {
            ConnectionFactory factory = ActiveMQUtil.factory;
            Connection connection = factory.createConnection();
            connection.start();
            Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
            Destination destination = session.createQueue("order-queue");
            MessageProducer producer = session.createProducer(destination);
            for (int i = 0; i < 20; i ++) {
                TextMessage message = session.createTextMessage("message-" + i);
                message.setStringProperty(CompositeDataConstants.JMSXGROUP_ID, i % 2 + "");
                producer.send(message);
            }
            session.close();
            connection.close();
        }
    }

    1.2.2 消费者消费消息

    @Slf4j
    public class OrderConsumer {
    
        public static void main(String[] args) throws JMSException, InterruptedException {
            ConnectionFactory factory = ActiveMQUtil.factory;
            Connection connection = factory.createConnection();
            connection.start();
            for (int i = 1; i <= 2; i ++) {
                new Thread(() -> {
                    try {
                        Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
                        Destination destination = session.createQueue("order-queue");
                        MessageConsumer consumer = session.createConsumer(destination);
                        TextMessage message = (TextMessage) consumer.receive(1000);
                        while (message != null) {
                            log.info("receive msg:" + message.getText() + ", group:" + message.getStringProperty(CompositeDataConstants.JMSXGROUP_ID));
                            message = (TextMessage) consumer.receive(1000);
                        }
                    }catch (Exception e) {
                        e.printStackTrace();
                    }
                }).start();
            }
            TimeUnit.HOURS.sleep(1);
        }
    }

    先启动消费者,再启动生产者
    输出:

    可以发现,线程Thread-2总是消费group=0的消息,线程Thread-3总是消费group=1的消息

    2 顺序消费

    从ActiveMQ4.X版本开始支持ExclusiveConsumer(或者说是Exclusive Queues)。Broker会从多个Consumer中挑选一个Consumer来处理所有的消息,从而保证消息的有序处理。如果这个Consumer失效,那么Broker会自动切换到其他的Consumer。
    可以通过Destination的Option来创建一个Exclusive Consumer,如下:
    queue = new ActiveMQQueue("Test.Queue?consumer.exclusive=true");
    consumer = session.createConsumer(queue);

    这里对上述代码稍作修改,设置消费者独占模式

    同样先启动消费者,在启动生产者,输出

    可以看到,所有的消息只被一个消费者消费

    展开全文
  • 链表:链表是一物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成,分为以下三: ...

    关于单链表的一点小心得

    • 链表:链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成,分为以下三种:

       		单向链表 (Singly linked lis)
       	    双向链表 (Doubly linked list)                        
       	    循环链表 (Circular linked list)          
      

      而今天我要说的是单链表,单链表作为最简单的链表结构但却也很神奇。

      单链表:

      用一组地址任意的存储单元存放线性表中的数据元素,链表当中的数据是以结点来表示的,链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的,每个结点只有一个链域的链表称为单链表。

      那什么叫结点呢?
      结点:元素(数据元素的映象)+指针(指示后继元素存储位置),具体的就是:data+next;

       data域:存放结点指的数据域
       next域:存放节点的直接后继的地址(位置)的指针域
      

    链表与我们以往所学的数组不同,我们没办法随便访问链表当中的值,我们只能通过挨个遍历的方式得到我们想要位置的元素,时间复杂度为o(N)时间,这时候有人有疑问了,既然链表没办法直接通过元素下标来访问,那还不如数组或者说顺序表好用,我们为啥使用这样一种数据结构呢?
    通过下面的讲述你会知道了;

    先搞几个单链表的简单操作:

    添加

    添加:如果我们想要给给定结点prev进行之后添加新值;我们要进行下面几步:

    1:使用给定值初始化新节点cur
    

    在这里插入图片描述

     	2将cur的next字段链接到prev下一个节点next
    

    在这里插入图片描述

    3:将prev中的next字段链接到cur
    

    在这里插入图片描述
    与数组相比,我们不用移动插入后方全部的元素,因此我们可以在时间复杂度为o(1)内完成成将新结点插入到链表当中,比数组的o(n)高效许多

    众所周知,我们使用头结点来代表整个列表,因此在列表的开头添加新节点时更新头结点head至关重要,具体操作为:

    1:初始化一个新节点cur
    2:将新节点链接到我们的原始头结点head
    3:将cur指定为head
    

    第二种操作

    删除

    首先找到cur的上一个结点prev及其下一个结点next
    

    在这里插入图片描述

    然后链接prev到cur的下一个结点next
    

    在这里插入图片描述
    在我们的第一步中,我们需要找出prev和next,使用cur的参考字段很容易找到next,但是我们必须从头结点遍历链表,以找出prev,它的时间复杂度时间为o(n),空间复杂度为o(1).如果删除的是第一个头结点,我们就在只需要简单的将下一个结点分配给head就好了。
    下面附加上十二中单链表的操作
    (1):初始化一个单链表

    Linklist::Linklist()
    {
    	head = new Elemtype;
    	head->data = 0;               //将头结点的数据域定义为0
    	head->next = NULL;            //头结点的下一个定义为NULL
    }
    

    (2):销毁一个单链表和创建一个单链表

    Linklist::~Linklist()
    {
    	delete head;                 //删除头结点
    }
    void Linklist::CreateLinklist(int n)
    {
    	Elemtype *pnew, *ptemp;
    	ptemp = head;
    	if (n < 0) {       //当输入的值有误时,处理异常
    		cout << "输入的节点个数有误" << endl;
    		exit(EXIT_FAILURE);
    	}
    	for (int i = 0; i < n;i++) {        //将值一个一个插入单链表中
    		pnew = new Elemtype;
    		cout << "请输入第" << i + 1 << "个值: " ;
    		cin >> pnew->data;
    		pnew->next = NULL;          //新节点的下一个地址为NULL
    		ptemp->next = pnew;         //当前结点的下一个地址设为新节点
    		ptemp = pnew;               //将当前结点设为新节点
    	}
    }
    

    (3):遍历一个单链表

    void Linklist::TravalLinklist()
    {
    	if (head == NULL || head->next ==NULL) {
    		cout << "链表为空表" << endl;
    	}
    	Elemtype *p = head;                 //另指针指向头结点
    	while (p->next != NULL)        //当指针的下一个地址不为空时,循环输出p的数据域
    	{
    		p = p->next;               //p指向p的下一个地址
    		cout << p->data << " ";
    	}
    }
    

    (4):获取线性表的长度

    int Linklist::GetLength()
    {
    	int count = 0;                  //定义count计数
    	Elemtype *p = head->next;           //定义p指向头结点
    	while (p != NULL)                //当指针的下一个地址不为空时,count+1
    	{
    		count++;
    		p = p->next;                //p指向p的下一个地址
    	}
    	return count;                   //返回count的数据
    }
    

    (5):判断单链表是否为空

    bool Linklist::IsEmpty()
    {
    	if (head->next == NULL) {
    		return true;
    	}
    	return false;
    }
    

    (6):查找指定节点

    Elemtype * Linklist::Find(DataType data)
    {
    	Elemtype * p = head;
    	if (p == NULL) {                           //当为空表时,报异常
    		cout << "此链表为空链表" << endl;
    		return ERROR;
    	}
    	else
    	{
    		while (p->next != NULL)               //循环每一个节点
    		{
    			if (p->data == data) {
    				return p;                     //返回指针域
    			}
    			p = p->next;
    		}
    		return NULL;                           //未查询到结果
    	}
    }
    
    (7):尾插法
    
    void Linklist::InsertElemAtEnd(DataType data)
    {
    	Elemtype * newNode = new Elemtype;    //定义一个Node结点指针newNode
    	newNode->next = NULL;         //定义newNode的数据域和指针域
    	newNode->data = data;
    	Elemtype * p = head;              //定义指针p指向头结点
    	if (head == NULL) {           //当头结点为空时,设置newNode为头结点
    		head = newNode;
    	}
    	else                          //循环知道最后一个节点,将newNode放置在最后
    	{
    		while (p->next != NULL)
    		{
    			p = p->next;
    		}
    		p->next = newNode;
    	}
    }
    

    (8):指定位置插入元素

    void Linklist::InsertElemAtIndex(DataType data,int n)
    {
    	if (n<1 || n>GetLength())                   //输入有误报异常
    		cout << "输入的值错误" << endl;
    	else
    	{
    		Elemtype * ptemp = new Elemtype;        //创建一个新的节点
    		ptemp->data = data;                     //定义数据域
    		Elemtype * p = head;                    //创建一个指针指向头结点
    		int i = 1;
    		while (n > i)                           //遍历到指定的位置
    		{
    			p = p->next;
    			i++;
    		}
    		ptemp->next = p->next;                 //将新节点插入到指定位置
    		p->next = ptemp;
    	}
    }
    

    (9):在头部插入数据

    void Linklist::InsertElemAtHead(DataType data)
    {
    	Elemtype * newNode = new Elemtype;    //定义一个Node结点指针newNode
    	newNode->data = data;
    	Elemtype * p = head;              //定义指针p指向头结点
    	if (head == NULL) {           //当头结点为空时,设置newNode为头结点
    		head = newNode;
    	}
    	newNode->next = p->next;          //将新节点插入到指定位置
    	p->next = newNode;
    }
    

    (10):在尾部删除元素

    void Linklist::DeleteElemAtEnd()
    {
    	Elemtype * p = head;          //创建一个指针指向头结点
    	Elemtype * ptemp = NULL;      //创建一个占位节点
    	if (p->next == NULL) {        //判断链表是否为空
    		cout << "单链表空" << endl;
    	}
    	else
    	{
    		while (p->next != NULL)   //循环到尾部的前一个
    		{
    			ptemp = p;            //将ptemp指向尾部的前一个节点
    			p = p->next;          //p指向最后一个节点
    		}
    		delete p;                //删除尾部节点
    		p = NULL;
    		ptemp->next = NULL;
    	}
    }
    

    (11):删除指定元素

    void Linklist::DeleteElemAtPoint(DataType data)
    {
    	Elemtype * ptemp = Find(data);    //查找到指定数据的节点位置
    	if (ptemp == head->next) {        //判断是不是头结点的下一个节点,如果是就从头部删了它
    		DeleteElemAtHead();
    	}
    	else
    	{
    		Elemtype * p = head;          //p指向头结点
    		while (p->next != ptemp)      //p循环到指定位置的前一个节点
    		{
    			p = p->next;
    		}
    		p->next = ptemp->next;         //删除指定位置的节点
    		delete ptemp;
    		ptemp = NULL;
    	}
    
    }
    

    (12):在头部删除节点

    void Linklist::DeleteElemAtHead()
    {
    	Elemtype * p = head;
    	if (p == NULL || p->next == NULL) {   //判断是否为空表,报异常
    		cout << "该链表为空表" << endl;
    	}
    	else
    	{
    		Elemtype * ptemp = NULL;      //创建一个占位节点
    		p = p->next;
    		ptemp = p->next;              //将头结点的下下个节点指向占位节点
    		delete p;                     //删除头结点的下一个节点
    		p = NULL;
    		head->next = ptemp;           //头结点的指针更换
    	}
    }
    

    (13)删除所有元素

    void Linklist::DeleteAll()
    {
    	Elemtype * p = head->next;
    	Elemtype * ptemp = new Elemtype;
    	while (p != NULL)                    //在头结点的下一个节点逐个删除节点
    	{
    		ptemp = p;
    		p = p->next;
    		head->next = p;
    		ptemp->next = NULL;
    		delete ptemp;
    	}
    	head->next = NULL;                 //头结点的下一个节点指向NULL
    }
    

    下面是完整的测试函数

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cassert>
    #include<vector>
    using namespace std;
    typedef int DataType;
    #define Node Elemtype
    #define ERROR NULL
    class Node
    {
    public:
        int data;
        Node *next;
    };
    class Linklist
    {
    public:
    	Linklist();					  //构建一个单链表;
    	~Linklist();                  //销毁一个单链表;
    	void CreateLinklist(int n);   //创建一个单链表
    	void TravalLinklist();        //遍历线性表
    	int GetLength();              //获取线性表长度
    	bool IsEmpty();               //判断单链表是否为空
    	Elemtype * Find(DataType data); //查找节点
    	void InsertElemAtEnd(DataType data);            //在尾部插入指定的元素
    	void InsertElemAtIndex(DataType data,int n);    //在指定位置插入指定元素
    	void InsertElemAtHead(DataType data);           //在头部插入指定元素
    	void DeleteElemAtEnd();       //在尾部删除元素
    	void DeleteAll();             //删除所有数据
    	void DeleteElemAtPoint(DataType data);     //删除指定的数据
    	void DeleteElemAtHead();      //在头部删除节点
    private:
    	Elemtype * head;              //头结点
    };
    
    //初始化单链表
    Linklist::Linklist()
    {
    	head = new Elemtype;
    	head->data = 0;               //将头结点的数据域定义为0
    	head->next = NULL;            //头结点的下一个定义为NULL
    }
    
    //销毁单链表
    Linklist::~Linklist()
    {
    	delete head;                 //删除头结点
    }
    
    //创建一个单链表
    void Linklist::CreateLinklist(int n)
    {
    	Elemtype *pnew, *ptemp;
    	ptemp = head;
    	if (n < 0) {       //当输入的值有误时,处理异常
    		cout << "输入的节点个数有误" << endl;
    		exit(EXIT_FAILURE);
    	}
    	for (int i = 0; i < n;i++) {        //将值一个一个插入单链表中
    		pnew = new Elemtype;
    		cout << "请输入第" << i + 1 << "个值: " ;
    		cin >> pnew->data;
    		pnew->next = NULL;          //新节点的下一个地址为NULL
    		ptemp->next = pnew;         //当前结点的下一个地址设为新节点
    		ptemp = pnew;               //将当前结点设为新节点
    	}
    }
    
    //遍历单链表
    void Linklist::TravalLinklist()
    {
    	if (head == NULL || head->next ==NULL) {
    		cout << "链表为空表" << endl;
    	}
    	Elemtype *p = head;                 //另指针指向头结点
    	while (p->next != NULL)        //当指针的下一个地址不为空时,循环输出p的数据域
    	{
    		p = p->next;               //p指向p的下一个地址
    		cout << p->data << " ";
    	}
    }
    
    //获取单链表的长度
    int Linklist::GetLength()
    {
    	int count = 0;                  //定义count计数
    	Elemtype *p = head->next;           //定义p指向头结点
    	while (p != NULL)                //当指针的下一个地址不为空时,count+1
    	{
    		count++;
    		p = p->next;                //p指向p的下一个地址
    	}
    	return count;                   //返回count的数据
    }
    
    //判断单链表是否为空
    bool Linklist::IsEmpty()
    {
    	if (head->next == NULL) {
    		return true;
    	}
    	return false;
    }
    
    //查找节点
    Elemtype * Linklist::Find(DataType data)
    {
    	Elemtype * p = head;
    	if (p == NULL) {                           //当为空表时,报异常
    		cout << "此链表为空链表" << endl;
    		return ERROR;
    	}
    	else
    	{
    		while (p->next != NULL)               //循环每一个节点
    		{
    			if (p->data == data) {
    				return p;                     //返回指针域
    			}
    			p = p->next;
    		}
    		return NULL;                           //未查询到结果
    	}
    }
    
    //在尾部插入指定的元素
    void Linklist::InsertElemAtEnd(DataType data)
    {
    	Elemtype * newNode = new Elemtype;    //定义一个Node结点指针newNode
    	newNode->next = NULL;         //定义newNode的数据域和指针域
    	newNode->data = data;
    	Elemtype * p = head;              //定义指针p指向头结点
    	if (head == NULL) {           //当头结点为空时,设置newNode为头结点
    		head = newNode;
    	}
    	else                          //循环知道最后一个节点,将newNode放置在最后
    	{
    		while (p->next != NULL)
    		{
    			p = p->next;
    		}
    		p->next = newNode;
    	}
    }
    
    //在指定位置插入指定元素
    void Linklist::InsertElemAtIndex(DataType data,int n)
    {
    	if (n<1 || n>GetLength())                   //输入有误报异常
    		cout << "输入的值错误" << endl;
    	else
    	{
    		Elemtype * ptemp = new Elemtype;        //创建一个新的节点
    		ptemp->data = data;                     //定义数据域
    		Elemtype * p = head;                    //创建一个指针指向头结点
    		int i = 1;
    		while (n > i)                           //遍历到指定的位置
    		{
    			p = p->next;
    			i++;
    		}
    		ptemp->next = p->next;                 //将新节点插入到指定位置
    		p->next = ptemp;
    	}
    }
    
    //在头部插入指定元素
    void Linklist::InsertElemAtHead(DataType data)
    {
    	Elemtype * newNode = new Elemtype;    //定义一个Node结点指针newNode
    	newNode->data = data;
    	Elemtype * p = head;              //定义指针p指向头结点
    	if (head == NULL) {           //当头结点为空时,设置newNode为头结点
    		head = newNode;
    	}
    	newNode->next = p->next;          //将新节点插入到指定位置
    	p->next = newNode;
    }
    
    //在尾部删除元素
    void Linklist::DeleteElemAtEnd()
    {
    	Elemtype * p = head;          //创建一个指针指向头结点
    	Elemtype * ptemp = NULL;      //创建一个占位节点
    	if (p->next == NULL) {        //判断链表是否为空
    		cout << "单链表空" << endl;
    	}
    	else
    	{
    		while (p->next != NULL)   //循环到尾部的前一个
    		{
    			ptemp = p;            //将ptemp指向尾部的前一个节点
    			p = p->next;          //p指向最后一个节点
    		}
    		delete p;                //删除尾部节点
    		p = NULL;
    		ptemp->next = NULL;
    	}
    }
    
    //删除所有数据
    void Linklist::DeleteAll()
    {
    	Elemtype * p = head->next;
    	Elemtype * ptemp = new Elemtype;
    	while (p != NULL)                    //在头结点的下一个节点逐个删除节点
    	{
    		ptemp = p;
    		p = p->next;
    		head->next = p;
    		ptemp->next = NULL;
    		delete ptemp;
    	}
    	head->next = NULL;                 //头结点的下一个节点指向NULL
    }
    
    //删除指定的数据
    void Linklist::DeleteElemAtPoint(DataType data)
    {
    	Elemtype * ptemp = Find(data);    //查找到指定数据的节点位置
    	if (ptemp == head->next) {        //判断是不是头结点的下一个节点,如果是就从头部删了它
    		DeleteElemAtHead();
    	}
    	else
    	{
    		Elemtype * p = head;          //p指向头结点
    		while (p->next != ptemp)      //p循环到指定位置的前一个节点
    		{
    			p = p->next;
    		}
    		p->next = ptemp->next;         //删除指定位置的节点
    		delete ptemp;
    		ptemp = NULL;
    	}
    
    }
    
    //在头部删除节点
    void Linklist::DeleteElemAtHead()
    {
    	Elemtype * p = head;
    	if (p == NULL || p->next == NULL) {   //判断是否为空表,报异常
    		cout << "该链表为空表" << endl;
    	}
    	else
    	{
    		Elemtype * ptemp = NULL;      //创建一个占位节点
    		p = p->next;
    		ptemp = p->next;              //将头结点的下下个节点指向占位节点
    		delete p;                     //删除头结点的下一个节点
    		p = NULL;
    		head->next = ptemp;           //头结点的指针更换
    	}
    }
    
    //测试函数
    int main()
    {
    	Linklist l;
    	int i;
    	cout << "1.创建单链表   2.遍历单链表   3.获取单链表的长度   4.判断单链表是否为空   5.获取节点\n";
    	cout << "6.在尾部插入指定元素   7.在指定位置插入指定元素   8.在头部插入指定元素\n";
    	cout<<"9.在尾部删除元素   10.删除所有元素   11.删除指定元素   12.在头部删除元素   0.退出" << endl;
    	do
    	{
    		cout << "请输入要执行的操作: ";
    		cin >> i;
    		switch (i)
    		{
    		case 1:
    			int n;
    			cout << "请输入单链表的长度: ";
    			cin >> n;
    			l.CreateLinklist(n);
    			break;
    		case 2:
    			l.TravalLinklist();
    			break;
    		case 3:
    			cout << "该单链表的长度为" << l.GetLength() << endl;
    			break;
    		case 4:
    			if (l.IsEmpty() == 1)
    				cout << "该单链表是空表" << endl;
    			else
    			{
    				cout << "该单链表不是空表" << endl;
    			}
    			break;
    		case 5:
    			DataType data;
    			cout << "请输入要获取节点的值: ";
    			cin >> data;
    			cout << "该节点的值为" << l.Find(data)->data << endl;
    			break;
    		case 6:
    			DataType endData;
    			cout << "请输入要在尾部插入的值: ";
    			cin >> endData;
    			l.InsertElemAtEnd(endData);
    			break;
    		case 7:
    			DataType pointData;
    			int index;
    			cout << "请输入要插入的数据: ";
    			cin >> pointData;
    			cout << "请输入要插入数据的位置: ";
    			cin >> index;
    			l.InsertElemAtIndex(pointData, index);
    			break;
    		case 8:
    			DataType headData;
    			cout << "请输入要在头部插入的值: ";
    			cin >> headData;
    			l.InsertElemAtHead(headData);
    			break;
    		case 9:
    			l.DeleteElemAtEnd();
    			break;
    		case 10:
    			l.DeleteAll();
    			break;
    		case 11:
    			DataType pointDeleteData;
    			cout << "请输入要删除的数据: ";
    			cin >> pointDeleteData;
    			l.DeleteElemAtPoint(pointDeleteData);
    			break;
    		case 12:
    			l.DeleteElemAtHead();
    			break;
    		default:
    			break;
    		}
    	}while (i != 0);
    
    	system("pause");
        return 0;
    }
    
    

    如有不足,还望大佬帮忙指出,第一次写CSDN的文章,心里慌得一批。。。。

    展开全文
  • 前两篇博文中简单整理了普通广播,其实还有有序广播,有序广播在开发中也是比不可少的,可以给广播接收者设定优先级来控制接受顺序,并却可以中断广播传递等等。 一、两Broadcast:  · 普通广播(Normal ...

      前两篇博文中简单整理了普通广播,其实还有有序广播,有序广播在开发中也是比不可少的,可以给广播接收者设定优先级来控制接受顺序,并却可以中断广播传递等等。

    一、两种Broadcast:

      · 普通广播(Normal Broadcast):用sendBroadcast()方法发送。

      普通广播是完全异步的,逻辑上可以在同一时刻被所有匹配的接受者接收到,消息传递效率高,缺点是接受者不能将处理结果传递给下一个接收者,也无法终止广播传播。

      · 有序广播(Ordered Broadcast):用sendOrderedBroadcast()方法发送。

      有序广播的接收者们将按照事先生命的优先级依次接收,数越大优先级越高(取值范围:-1000~10000),优先级可以声明在<intent-filter android:priority="n".../>,也可以调用IntentFilter对象的setPriority设置。并且接收者可以终止传播(调用abortBroadcast()方法即可终止),一旦终止后面接收者就无法接受广播。另外,接受者可以将处理结果存入数据(可通过setResultExtras(Bundle)方法将数据存入Broadcast),当做Broadcast再传递给下一级接收者(可通过代码Bundle bundle = getResultExtras(true)获取上一级传递过来的数据)。

      短信拦截原理:系统收到短信,发出的Broadcast属于有序广播,程序就可以通过设定优先级先接收到通知,然后终止传递。

    二、举个例子(有序广播):

      1、首先创建两个BroadcastReceiver。让第一个receive接收到广播后中断。

      MyReceiver.java

    1 public class MyReceiver extends BroadcastReceiver {
    2 
    3     @Override
    4     public void onReceive(Context context, Intent intent) {
    5         System.out.println("MyReceiver接受到消息");
    6         abortBroadcast(); //中断广播,不会再响比它有优先级低得广播再传播下去了
    7     }
    8 }

      MyReceiver1.java

    1 public class MyReceiver1 extends BroadcastReceiver {
    2 
    3     @Override
    4     public void onReceive(Context context, Intent intent) {
    5         System.out.println("MyReceiver1接受到消息");
    6     }
    7 }

      2、然后将两个receiver的action在AndroidManifest.xml文件中配置成一样的,并且设置成不同的优先级,代码如下:

     1      <receiver android:name=".MyReceiver">
     2             <!-- priority优先级:数字越高优先级越高 -->
     3             <intent-filter android:priority="5" >
     4                 <action android:name="com.codingblock.myreceiver.intent.action.MyReceiver"/>
     5             </intent-filter>
     6         </receiver>
     7         <receiver android:name=".MyReceiver1">
     8             <intent-filter android:priority="4">
     9                 <action android:name="com.codingblock.myreceiver.intent.action.MyReceiver"/>
    10             </intent-filter>
    11         </receiver>

      3.最后在MainActivity中发送广播

     1 public class MainActivity extends Activity {
     2 
     3     Button btn_send_receiver;
     4     @Override
     5     protected void onCreate(Bundle savedInstanceState) {
     6         super.onCreate(savedInstanceState);
     7         setContentView(R.layout.activity_main);
     8         btn_send_receiver = (Button)findViewById(R.id.btn_send_receiver);
     9         btn_send_receiver.setOnClickListener(new OnClickListener() {
    10             
    11             @Override
    12             public void onClick(View v) {
    13                 Intent intent = new Intent();
    14                 intent.setAction("com.codingblock.myreceiver.intent.action.MyReceiver");
    15                 sendOrderedBroadcast(intent, null);//有序广播需要用sendOrderedBroadcast()方法发送
    16             }
    17         });
    18     }
    19 }

      布局文件只有一个Button,比较简单,在此就不贴出了。

      通过运行测试就会发现,点击发送消息按钮后只有MyReceiver接收到了消息,广播就被中断了。日志如下:

     

      

    转载于:https://www.cnblogs.com/codingblock/p/4856559.html

    展开全文
  • 2.10.2 常见错误十二:调研工作表现不职业 24 2.11 调研工作方法推荐 24 2.11.1每日调研流程 24 2.11.2 访谈成功的九个要点 25 2.11.3 良好的结构化调研顺序 25 2.11.4 售前和售后调研的不同 25 2.11.5 如何写调研...
  • 2.10.2 常见错误十二:调研工作表现不职业 24 2.11 调研工作方法推荐 24 2.11.1每日调研流程 24 2.11.2 访谈成功的九个要点 25 2.11.3 良好的结构化调研顺序 25 2.11.4 售前和售后调研的不同 25 2.11.5 如何写调研...
  • 库存分析-源码

    2021-03-04 11:33:07
    提供了十二(12)不同股票在两年内的表现数据。 交易量,交易日开始时每只股票的最高价,最低价以及收盘价。 史蒂夫(Steve)将为父母提供易于理解的信息,这将使他们能够对决定买卖的任何股票进行良好的投资。 ...
  • 程序员二进制计算器 v1.36

    热门讨论 2014-07-16 16:21:43
    支持与、或、非、异或、移位(循环、逻辑、算术),直接读写二进制位,指定位段读、写、置1、清0、反转。 二进制数据表达方式多样,数据可以K、M、G等单位为后缀。 支持类C语言库函数调用。 结果可以各种进制、各种...
  • 128.mybatis 逻辑分页和物理分页的区别是什么? 129.mybatis 是否支持延迟加载?延迟加载的原理是什么? 130.说一下 mybatis 的一级缓存和二级缓存? 131.mybatis 和 hibernate 的区别有哪些? 132.mybatis 有哪些...
  • 例如,一个星期内只有七天,一年只有十二个月, 一个班每周有六门课程等等。如果把这些量说明为整型, 字符型或其它类型显然是不妥当的。 为此,C语言提供了一称为“枚举”的类型。在“枚举”类型的定义中列举出...
  • 11、有数组a[n],用java代码将数组元素顺序颠倒 80 12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 81 三. html&JavaScript&ajax部分 82 1. 判断第二个日期比第一...
  • asp.net面试题

    2011-05-27 17:56:26
    十二、下面哪个SQL语句完全正确( ) A.Select count(*) from (select top 10 * from table order by bb) tb group by cc B.update set bb = bb + 1 from table C.Select count(*) from (select distinct * from ...
  • Java面试宝典2010版

    2011-06-27 09:48:27
    11、有数组a[n],用java代码将数组元素顺序颠倒 80 12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 三. html&JavaScript&ajax部分 1. 判断第二个日期比第一个...
  • 最新Java面试宝典pdf版

    热门讨论 2011-08-31 11:29:22
    11、有数组a[n],用java代码将数组元素顺序颠倒 80 12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 81 三. html&JavaScript&ajax部分 82 1. 判断第二个日期比第一...
  • Java面试宝典-经典

    2015-03-28 21:44:36
    11、有数组a[n],用java代码将数组元素顺序颠倒 80 12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 81 三. html&JavaScript&ajax部分 82 1. 判断第二个日期比第一...
  • Java面试宝典2012版

    2012-12-03 21:57:42
    11、有数组a[n],用java代码将数组元素顺序颠倒 80 12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 81 三. html&JavaScript;&ajax;部分 82 1. 判断第二个日期...
  • java面试宝典2012

    2012-12-16 20:43:41
    11、有数组a[n],用java代码将数组元素顺序颠倒 87 12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 88 三. html&JavaScript;&ajax;部分 89 1. 判断第二个日期比第...
  • 11、有数组a[n],用java代码将数组元素顺序颠倒 80 12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 81 三. html&JavaScript;&ajax;部分 82 1. 判断第二个日期比第...
  • Java面试笔试资料大全

    热门讨论 2011-07-22 14:33:56
    11、有数组a[n],用java代码将数组元素顺序颠倒 80 12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 81 三. html&JavaScript&ajax部分 82 1. 判断第二个日期比第一...
  • Java面试宝典2012新版

    2012-06-26 19:20:00
    11、有数组a[n],用java代码将数组元素顺序颠倒 80 12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 81 三. html&JavaScript;&ajax;部分 82 1. 判断第二个日期比第...
  • @AfterThrowing: 用来处理当织入的代码抛出异常后的逻辑处理; @Around: 环绕,可以在切入点前后织入代码,并且可以自由的控制何时执行切点; 应用:使用自定义注解 和 AOP 切面统一打印出入参日志 1.2 自定义 ...
  • JAVA面试宝典2010

    2011-12-20 16:13:24
    11、有数组a[n],用java代码将数组元素顺序颠倒 80 12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 81 三. html&JavaScript&ajax部分 82 1. 判断第二个日期比第一...
  • 2.10.2 常见错误十二:调研工作表现不职业 24 2.11 调研工作方法推荐 24 2.11.1每日调研流程 24 2.11.2 访谈成功的九个要点 25 2.11.3 良好的结构化调研顺序 25 2.11.4 售前和售后调研的不同 25 2.11.5 如何写调研...
  • 操作系统概念第六版翻译版

    热门讨论 2012-08-05 13:11:37
    逻辑地址空间与物理地址空间 动态加载 动态链接与共享库 覆盖 交换 连续内存分配 内存保护 内存分配 碎片 分页 基本方法 硬件支持 保护 页表结构 共享页表 分段 基本方法 硬件 保护与共享 碎片 带有分页的分段 ?小结...
  • 逻辑地址空间与物理地址空间 动态加载 动态链接与共享库 覆盖 交换 连续内存分配 内存保护 内存分配 碎片 分页 基本方法 硬件支持 保护 页表结构 共享页表 分段 基本方法 硬件 保护与共享 碎片 带有分页的分段 ?小结...
  • 十二生肖(鼠、牛、虎、兔、龙、蛇、马、羊、猴、鸡、狗、猪)排序为例: <p><img alt="array_demo" src=...
  • asp.net知识库

    2015-06-18 08:45:45
    .NET20 一简单的窗口控件UI状态控制方法 翻译MSDN文章 —— 泛型FAQ:最佳实践 Visual C# 3.0 新特性概览 C# 2.0会给我们带来什么 泛型技巧系列:如何提供类型参数之间的转换 C#2.0 - Object Pool 简单实现 ...
  • 46、java中有几方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?......................................................................................................

空空如也

空空如也

1 2
收藏数 40
精华内容 16
关键字:

十二种逻辑顺序