首页 文章 精选 留言 我的

精选列表

搜索[超融合软件],共10000篇文章
优秀的个人博客,低调大师

Hive解析Json数组超全讲解

2 --> 在Hive中会有很多数据是用Json格式来存储的,如开发人员对APP上的页面进行埋点时,会将多个字段存放在一个json数组中,因此数据平台调用数据时,要对埋点数据进行解析。接下来就聊聊Hive中是如何解析json数据的。 本文首发于公众号【五分钟学大数据】 Hive自带的json解析函数 1. get_json_object 语法:get_json_object(json_string, '$.key') 说明:解析json的字符串json_string,返回path指定的内容。如果输入的json字符串无效,那么返回NULL。这个函数每次只能返回一个数据项。 示例: selectget_json_object('{"name":"zhangsan","age":18}','$.name'); 结果: name zhangsan 如果既要解析name字段,也解析age字段,则可以这样写: selectget_json_object('{"name":"zhangsan","age":18}','$.name'),get_json_object('{"name":"zhangsan","age":18}','$.age'); 但是如果要解析的字段有很多,再这样写就太麻烦了,所以就有了 json_tuple 这个函数。 2. json_tuple 语法: json_tuple(json_string, k1, k2 ...) 说明:解析json的字符串json_string,可指定多个json数据中的key,返回对应的value。如果输入的json字符串无效,那么返回NULL。 示例: selectb.name,b.agefromtableNamealateralviewjson_tuple('{"name":"zhangsan","age":18}','name','age')basname,age; 结果: name age zhangsan 18 注意:上面的json_tuple函数中没有$. 如果在使用json_tuple函数时加上$.就会解析失败: selectb.name,b.agefromtableNamealateralviewjson_tuple('{"name":"zhangsan","age":18}','$.name','$.age')basname,age; 结果: name age NULL NULL 字段全是NULL,所以json_tuple函数不需要加$.了,否则会解析不到。 总结:json_tuple相当于get_json_object的优势就是一次可以解析多个json字段。但是如果我们有个json数组,这两个函数都无法处理。 Hive解析json数组 一、嵌套子查询解析json数组 如果有一个hive表,表中 json_str 字段的内容如下: json_str [{"website":"baidu.com","name":"百度"},{"website":"google.com","name":"谷歌"}] 我们想把这个字段解析出来,形成如下的结构: website name baidu.com 百度 google.com 谷歌 要解析这个json数组,仅用上面介绍的两个函数就解析不出来了,还需用到如下介绍的几个函数: explode函数 语法: explode(Array OR Map) 说明:explode()函数接收一个array或者map类型的数据作为输入,然后将array或map里面的元素按照每行的形式输出,即将hive一列中复杂的array或者map结构拆分成多行显示,也被称为列转行函数。 示例: --解析arrayhive>selectexplode(array('A','B','C'));OKABC--解析maphive>selectexplode(map('A',10,'B',20,'C',30));OKA10B20C30 regexp_replace函数 语法: regexp_replace(string A, string B, string C) 说明:将字符串A中的符合java正则表达式B的部分替换为C。注意,在有些情况下要使用转义字符,类似oracle中的regexp_replace函数。 示例: hive>selectregexp_replace('foobar','oo|ar','');OKfb 上述示例将字符串中的 oo 或 ar 替换为''。 有了上述几个函数,接下来我们来解析json_str字段的内容: 先将json数组中的元素解析出来,转化为每行显示: hive>SELECTexplode(split(regexp_replace(regexp_replace('[{"website":"baidu.com","name":"百度"},{"website":"google.com","name":"谷歌"}]','\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;'));OK{"website":"baidu.com","name":"百度"}{"website":"google.com","name":"谷歌"} 对上述sql进行简要说明: SELECTexplode(split(regexp_replace(regexp_replace('[{"website":"baidu.com","name":"百度"},{"website":"google.com","name":"谷歌"}]','\\[|\\]',''),将json数组两边的中括号去掉'\\}\\,\\{','\\}\\;\\{'),将json数组元素之间的逗号换成分号'\\;')以分号作为分隔符(split函数以分号作为分隔)); 为什么要将json数组元素之间的逗号换成分号?因为元素内的分隔也是逗号,如果不将元素之间的逗号换掉的话,后面用split函数分隔时也会把元素内的数据给分隔,这不是我们想要的结果。 上步已经把一个json数组转化为多个json字符串了,接下来结合son_tuple函数来解析json里面的字段: selectjson_tuple(explode(split(regexp_replace(regexp_replace('[{"website":"baidu.com","name":"百度"},{"website":"google.com","name":"谷歌"}]','\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;')),'website','name'); 执行上述语句,结果报错了:FAILED: SemanticException [Error 10081]: UDTF's are not supported outside the SELECT clause, nor nested in expressions 意思是UDTF函数不能写在别的函数内,也就是这里的explode函数不能写在json_tuple里面。 既然explode函数不能写在别的json_tuple里面,那我们可以用子查询方式,如下所示: selectjson_tuple(json,'website','name')from(selectexplode(split(regexp_replace(regexp_replace('[{"website":"baidu.com","name":"百度"},{"website":"google.com","name":"谷歌"}]','\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;'))asjson)t; 执行上述语句,没有报错,执行结果如下: www.baidu.com百度google.com谷歌 二 使用 lateral view 解析json数组 hive表中 goods_id 和 json_str 字段的内容如下: goods_id json_str 1,2,3 [{"source":"7fresh","monthSales":4900,"userCount":1900,"score":"9.9"},{"source":"jd","monthSales":2090,"userCount":78981,"score":"9.8"},{"source":"jdmart","monthSales":6987,"userCount":1600,"score":"9.0"}] 目的:把 goods_id 字段和 json_str 字段中的monthSales解析出来。 下面我们就开始解析: 拆分goods_id字段及将json数组转化成多个json字符串: selectexplode(split(goods_id,','))asgood_id,explode(split(regexp_replace(regexp_replace(json_str,'\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;'))assale_infofromtableName; 执行上述语句,结果报错:FAILED: SemanticException 3:0 Only a single expression in the SELECT clause is supported with UDTF's. Error encountered near token 'sale_info' 意思是用UDTF的时候,SELECT 只支持一个字段。而上述语句select中有两个字段,所以报错了。 那怎么办呢,要解决这个问题,还得再介绍一个hive语法: lateral view lateral view用于和split、explode等UDTF一起使用的,能将一行数据拆分成多行数据,在此基础上可以对拆分的数据进行聚合,lateral view首先为原始表的每行调用UDTF,UDTF会把一行拆分成一行或者多行,lateral view在把结果组合,产生一个支持别名表的虚拟表。 示例: 假设我们有一张用户兴趣爱好表 hobbies_table,它有两列数据,第一列是name,第二列是用户兴趣爱好的id_list,是一个数组,存储兴趣爱好的id值: name id_list zhangsan [1,2,3] lisi [3,4,5] 我们要统计所有兴趣id在所有用户中出现的次数: 对兴趣id进行解析: SELECTname,hobby_idFROMhobbies_tableLATERALVIEWexplode(id_list)tmp_tableAShobby_id; 上述sql执行结果: name hobby_id zhangsan 1 zhangsan 2 zhangsan 3 lisi 3 lisi 4 lisi 5 将id_list拆分完之后统计在用户中出现的次数就简单了,按照hobby_id进行分组聚合即可: SELECThobby_id,count(name)client_numFROMhobbies_tableLATERALVIEWexplode(id_list)tmp_tableAShobby_idgroupbyhobby_id; 结果: hobby_id client_num 1 1 2 1 3 2 4 1 5 1 介绍完 lateral view 之后,我们再来解决上面遇到的用UDTF的时候,SELECT 只支持一个字段的问题: selectgood_id,get_json_object(sale_json,'$.monthSales')asmonthSalesfromtableNameLATERALVIEWexplode(split(goods_id,','))goodsasgood_idLATERALVIEWexplode(split(regexp_replace(regexp_replace(json_str,'\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;'))salesassale_json; 注意:上述语句是三个表笛卡尔积的结果,所以此方式适用于数据量不是很大的情况。 上述语句执行结果如下: goods_id monthSales 1 4900 1 2090 1 6987 2 4900 2 2090 2 6987 3 4900 3 2090 3 6987 如果表中还有其他字段,我们可以根据其他字段筛选出符合结果的数据。 总结:lateral view通常和UDTF一起出现,为了解决UDTF不允许在select存在多个字段的问题。 公众号【五分钟学大数据】,大数据领域原创技术号,专注于大数据技术研究

优秀的个人博客,低调大师

了解HashMap数据结构,超详细!

点击蓝色“程序员的时光”关注我,标注“星标”,及时阅读最新技术文章 写在前面: 小伙伴儿们,大家好!今天来学习HashMap相关内容,作为面试必问的知识点,来深入了解一波! 思维导图: 学习框架图 1,HashMap集合简介 HashMap基于哈希表的Map接口实现,是以key-value存储形式存在,即主要用来存放键值对。HashMap的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。 JDK1.8之前的HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了节解决哈希碰撞(两个对象调用的hashCode方法计算的哈希码值一致导致计算的数组索引值相同)而存在的(“拉链法”解决冲突)。 JDK1.8之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(或者红黑树的边界值,默认为8)并且当前数组的长度大于64时,此时此索引位置上的所有数据改为使用红黑树存储。 数组里面都是key-value的实例,在JDK1.8之前叫做Entry,在JDK1.8之后叫做Node。 key-value实例 由于它的key、value都为null,所以在插入的时候会根据key的hash去计算一个index索引的值。计算索引的方法如下: /***根据key求index的过程*1,先用key求出hash值*/staticfinalinthash(Objectkey){inth;return(key==null)?0:(h=key.hashCode())^(h>>>16);}//2,再用公式index=(n-1)&hash(n是数组长度)inthash=hash(key);index=(n-1)&hash; 这里的Hash算法本质上就是三步:取key的hashCode值、高位运算、取模运算。 这样的话比如说put("A",王炸),插入了key为"A"的元素,这时候通过上述公式计算出插入的位置index,若index为3则结果如下(即hash("A")=3): 插入索引为3的结点 那么,HashMap中的链表又是干什么用的呢? 大家都知道数组的长度是有限的,在有限的长度里面使用哈希函数计算index的值时,很有可能插入的k值不同,但所产生的hash是相同的(也叫做哈希碰撞),这也就是哈希函数存在一定的概率性。就像上面的K值为A的元素,如果再次插入一个K值为a的元素,很有可能所产生的index值也为3,也就是即hash("a")=3;那这就形成了链表,这种解决哈希碰撞的方法也叫做拉链法。 同一个位置插入不同元素 当这个链表长度大于阈值8并且数组长度大于64则进行将链表变为红黑树。 补充: 将链表转换成红黑树前会判断,如果阈值大于8,但是数组长度小64,此时并不会将链表变为红黑树。而是选择进行数组扩容。 这样做的目的是因为数组比较小,尽量避开红黑树结构,这种情况下变为红黑树结构,反而会降低效率,因为红黑树需要进行左旋,右旋,变色这些操作来保持平衡。同事数组长度小于64时,搜索时间相对快一些。所以综上所述为了提高性能和减少搜索时间,底层在阈值大于8并且数组长度大于64时,链表才转换为红黑树。具体可以参考treeifyBin方法。 当然虽然增了红黑树作为底层数据结构,结构变得复杂了,但是阈值大于8并且数组长度大于64时,链表转换为红黑树时,效率也变得更高效。 特点: 存取无序的 键和值位置都可以是null,但是键位置只能是一个null 键位置是唯一的,底层的数据结构控制键的 jdk1.8前数据结构是:链表 + 数组 jdk1.8之后是 :链表 + 数组 + 红黑树 阈值(边界值) > 8 并且数组长度大于64,才将链表转换为红黑树,变为红黑树的目的是为了高效的查询。 2,HsahMap底层数据结构 2.1,HashMap存储数据的过程 每一个Node结点都包含键值对的key,value还有计算出来的hash值,还保存着下一个 Node 的引用 next(如果没有下一个 Node,next = null),来看看Node的源码: staticclassNode<K,V>implementsMap.Entry<K,V>{finalinthash;finalKkey;Vvalue;Node<K,V>next;...} HashMap存储数据需要用到put()方法,关于这些方法的详解,我们下节再说,这里简要说一下; publicstaticvoidmain(String[]args){HashMap<String,Integer>hmap=newHashMap<>();hmap.put("斑",55);hmap.put("镜",63);hmap.put("带土",25);hmap.put("鼬",9);hmap.put("佐助",43);hmap.put("斑",88);System.out.println(hmap);} 当创建HashMap集合对象的时候,在jdk1.8之前,构造方法中会创建很多长度是16的Entry[] table用来存储键值对数据的。在jdk1.8之后不是在HashMap的构造方法底层创建数组了,是在第一次调用put方法时创建的数组,Node[] table用来存储键值对数据的。 比方说我们向哈希表中存储"斑"-55的数据,根据K值("斑")调用String类中重写之后的hashCode()方法计算出值(数量级很大),然后结合数组长度采用取余((n-1)&hash)操作或者其他操作方法来计算出向Node数组中存储数据的空间的索引值。如果计算出来的索引空间没有数据,则直接将"斑"-55数据存储到数组中。跟上面的"A-王炸"数据差不多。 我们回到上方的数组图,如果此时再插入"A-蘑菇"元素,那么首先根据Key值("A")调用hashCode()方法结合数组长度计算出索引肯定也是3,此时比较后存储的"A-蘑菇"和已经存在的数据"A-王炸"的hash值是否相等,如果hash相等,此时发生hash碰撞。 那么底层会调用"A"所属类String中的equals方法比较两个key内容是否相等,若相等,则后添加的数据直接覆盖已经存在的Value,也就是"蘑菇"直接覆盖"王炸";若不相等,继续向下和其他数据的key进行比较,如果都不相等,则规划出一个节点存储数据。 两个结点key值比较,是否覆盖 2.2,哈希碰撞相关的问题 哈希表底层采用何种算法计算hash值?还有哪些算法可以计算出hash值? 底层是采用key的hashCode方法的值结合数组长度进行无符号右移(>>>)、按位异或(^)、按位与(&)计算出索引的 还可以采用:平方取中法,取余数,伪随机数法。这三种效率都比较低。而无符号右移16位异或运算效率是最高的。 当两个对象的hashCode相等时会怎么样? 会产生哈希碰撞,若key值内容相同则替换旧的value.否则连接到链表后面,链表长度超过阈值8就转换为红黑树存储。 何时发生哈希碰撞和什么是哈希碰撞,如何解决哈希碰撞? 只要两个元素的key计算的哈希值相同就会发生哈希碰撞。jdk8前使用链表解决哈希碰撞。jdk8之后使用链表+红黑树解决哈希碰撞。 如果两个键的hashcode相同,如何存储键值对? hashcode相同,通过equals比较内容是否相同。相同:则新的value覆盖之前的value 不相同:则将新的键值对添加到哈希表中 2.3,红黑树结构 当位于一个链表中的元素较多,即hash值相等但是内容不相等的元素较多时,通过key值依次查找的效率较低。而jdk1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度(阀值)超过 8 时且当前数组的长度 > 64时,将链表转换为红黑树,这样大大减少了查找时间。jdk8在哈希表中引入红黑树的原因只是为了查找效率更高。 红黑树结构 JDK 1.8 以前 HashMap 的实现是 数组+链表,即使哈希函数取得再好,也很难达到元素百分百均匀分布。当 HashMap 中有大量的元素都存放到同一个桶中时,这个桶下有一条长长的链表,这个时候 HashMap 就相当于一个单链表,假如单链表有 n 个元素,遍历的时间复杂度就是 O(n),完全失去了它的优势。针对这种情况,JDK 1.8 中引入了 红黑树(查找时间复杂度为 O(logn))来优化这个问题。当链表长度很小的时候,即使遍历,速度也非常快,但是当链表长度不断变长,肯定会对查询性能有一定的影响,所以才需要转成树。 2.4,存储流程图 HashMap存放数据是用的put方法,put 方法内部调用的是 putVal() 方法,所以对 put 方法的分析也是对 putVal 方法的分析,整个过程比较复杂,流程图如下: 来看看put()源码: publicVput(Kkey,Vvalue){//对key的hashCode()做hash,调用的是putVal方法returnputVal(hash(key),key,value,false,true);}finalVputVal(inthash,Kkey,Vvalue,booleanonlyIfAbsent,booleanevict){Node<K,V>[]tab;Node<K,V>p;intn,i;/*1,tab为空则开始创建,2,(tab=table)==null表示将空的table赋值给tab,然后判断tab是否等于null,第一次肯定是null3,(n=tab.length)==0表示没有为table分配内存 4,tab为空,执行代码 n =(tab = resize()).length;进行扩容。并将初始化好的数组长度赋值给n.5,执行完n=(tab=resize()).length,数组tab每个空间都是null*/if((tab=table)==null||(n=tab.length)==0)//调用resize()方法进行扩容n=(tab=resize()).length;/*1,i=(n-1)&hash表示计算数组的索引赋值给i,即确定元素存放在哪个桶中2,p=tab[i=(n-1)&hash]表示获取计算出的位置的数据赋值给节点p3,(p=tab[i=(n-1)&hash])==null判断节点位置是否等于null,如果为null,则执行代码:tab[i]= newNode(hash, key, value, null);根据键值对创建新的节点放入该位置的桶中小结:如果当前桶没有哈希碰撞冲突,则直接把键值对插入空间位置*/if((p=tab[i=(n-1)&hash])==null)//节点位置为null,则直接进行插入操作tab[i]=newNode(hash,key,value,null);//节点位置不为null,表示这个位置已经有值了,于是需要进行比较hash值是否相等else{Node<K,V>e;Kk;/*比较桶中第一个元素(数组中的结点)的hash值和key是否相等1,p.hash==hash中的p.hash表示原来存在数据的hash值hash表示后添加数据的hash值比较两个hash值是否相等 2,(k = p.key)== key :p.key获取原来数据的key赋值给k key表示后添加数据的key 比较两个key的地址值是否相等 3,key != null && key.equals(k):能够执行到这里说明两个key的地址值不相等,那么先判断后添加的key是否等于null,如果不等于null再调用equals方法判断两个key的内容是否相等*/if(p.hash==hash&&((k=p.key)==key||(key!=null&&key.equals(k))))/*说明:两个元素哈希值相等(哈希碰撞),并且key的值也相等将旧的元素整体对象赋值给e,用e来记录*/e=p;// hash值不相等或者key不相等;判断p是否为红黑树结点elseif(pinstanceofTreeNode)//是红黑树,调用树的插入方法e=((TreeNode<K,V>)p).putTreeVal(this,tab,hash,key,value);//说明是链表节点,这时进行插入操作else{/*1,如果是链表的话需要遍历到最后节点然后插入2,采用循环遍历的方式,判断链表中是否有重复的key*/for(intbinCount=0;;++binCount){/*1)e=p.next获取p的下一个元素赋值给e2)(e=p.next)==null判断p.next是否等于null,等于null,说明p没有下一个元素,那么此时到达了链表的尾部,还没有找到重复的key,则说明HashMap没有包含该键将该键值对插入链表中*/if((e=p.next)==null){p.next=newNode(hash,key,value,null);//插入后发现链表长度大于8,转换成红黑树结构if(binCount>=TREEIFY_THRESHOLD-1)//转换为红黑树treeifyBin(tab,hash);break;}//key值以及存在直接覆盖valueif(e.hash==hash&&((k=e.key)==key||(key!=null&&key.equals(k))))break;p=e;}}//若结点为null,则不进行插入操作if(e!=null){VoldValue=e.value;if(!onlyIfAbsent||oldValue==null)e.value=value;afterNodeAccess(e);returnoldValue;}}//修改记录次数++modCount;//判断实际大小是否大于threshold阈值,如果超过则扩容if(++size>threshold)resize();//插入后回调afterNodeInsertion(evict);returnnull;} 小结: 根据哈希表中元素个数确定是 扩容还是树形化 如果是树形化遍历桶中的元素,创建相同个数的树形节点,复制内容,建立起联系 然后让桶中的第一个元素指向新创建的树根节点,替换桶的链表内容为树形化内容 3,HashMap的扩容机制 我们知道,数组的容量是有限的,多次插入数据的话,到达一定数量就会进行扩容;先来看两个问题 什么时候需要扩容? 当HashMap中的元素个数超过数组长度loadFactor(负载因子)时,就会进行数组扩容,loadFactor的默认值是0.75,这是一个折中的取值。也就是说,默认情况下,数组大小为16,那么当HashMap中的元素个数超过16×0.75=12(这个值就是阈值)的时候,就把数组的大小扩展为2×16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常耗性能的操作,所以如果我们已经预知HashMap中元素的个数,那么预知元素的个数能够有效的提高HashMap的性能。 怎么进行扩容的? HashMap在进行扩容时使用 resize() 方法,计算 table 数组的新容量和 Node 在新数组中的新位置,将旧数组中的值复制到新数组中,从而实现自动扩容。因为每次扩容都是翻倍,与原来计算的 (n-1)&hash的结果相比,只是多了一个bit位,所以节点要么就在原来的位置,要么就被分配到"原位置+旧容量"这个位置。 因此,我们在扩充HashMap的时候,不需要重新计算hash,只需要看看原来hash值新增的那个bit是1还是0就可以了,是0的话索引没变,是1的话索引变成“原索引+oldCap(原位置+旧容量)”。这里不再详细赘述,可以看看下图为16扩充为32的resize示意图: hashmap扩容 4,HashMap数组长度为什么是2的次幂 我们先看看它的成员变量: 序列化版本号 privatestaticfinallongserialVersionUID=362498820763181265L; 集合的初始化容量initCapacity //默认的初始容量是16--1<<4相当于1*2的4次方---1*16staticfinalintDEFAULT_INITIAL_CAPACITY=1<<4; 初始化容量默认是16,容量过大,遍历时会减慢速度,效率低;容量过小,那么扩容的次数变多,非常耗费性能。 负载因子 /***Theloadfactorusedwhennonespecifiedinconstructor.*/staticfinalfloatDEFAULT_LOAD_FACTOR=0.75f; 初始默认值为0.75,若过大,会导致哈希冲突的可能性更大;若过小,扩容的次数也会提高。 为什么必须是2的n次幂? 当向HashMap中添加一个元素的时候,需要根据key的hash值,去确定其在数组中的具体位置。HashMap为了提高存取效率,要尽量较少碰撞,就是要尽量把数据分配均匀,每个链表长度大致相同,这个实现就在把数据存到哪个链表中的算法。 这个算法实际就是取模,hash%length,计算机中直接求余效率不如位移运算。所以源码中做了优化,使用 hash&(length-1),而实际上hash%length等于hash&(length-1)的前提是length是2的n次幂。 如果输入值不是2的幂会怎么样? 如果数组长度不是2的n次幂,计算出的索引特别容易相同,及其容易发生hash碰撞,导致其余数组空间很大程度上并没有存储数据,链表或者红黑树过长,效率降低。 小结: 1,当根据key的hash确定其在数组的位置时,如果n为2的幂次方,可以保证数据的均匀插入,如果n不是2的幂次方,可能数组的一些位置永远不会插入数据,浪费数组的空间,加大hash冲突。 2,一般可能会想通过 % 求余来确定位置,这样也可以,只不过性能不如 & 运算。而且当n是2的幂次方时:hash & (length - 1) == hash % length 3,因此,HashMap 容量为2次幂的原因,就是为了数据的的均匀分布,减少hash冲突,毕竟hash冲突越大,代表数组中一个链的长度越大,这样的话会降低hashmap的性能 好了,今天就先分享到这里了,下期继续给大家带来HashMap面试内容!更多干货、优质文章,欢迎关注我的原创技术公众号~ 文章好看点这里 本文分享自微信公众号 - 程序员的时光(gh_9211ec727426)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

android超简单短信接收——中级编

短信 short message service,简称SMS 是用户通过手机或其他电信终端直接发送或接收的文字或数字信息,用户每次能接收和发送短信的字符数,是160个英文或数字字符,或者70个中文字符。现在我通过Emulator Control向5554发送短信,如果5554收到短信将会提示,下面我们先看一下发来的短信提示图: 我们看一下方法类: packagecom.smart.sms; importandroid.content.BroadcastReceiver; importandroid.content.Context; importandroid.content.Intent; importandroid.os.Bundle; importandroid.telephony.SmsMessage; importandroid.widget.Toast; publicclassSmsReceiverextendsBroadcastReceiver{ @Override publicvoidonReceive(Contextcontext,Intentintent){ if("android.provider.Telephony.SMS_RECEIVED".equals(intent.getAction())){ StringBuildersb=newStringBuilder(); //接收由SMS传过来的数据 Bundlebundle=intent.getExtras(); //判断是否有数据 if(bundle!=null){ //通过pdus可以获得接收到的所有短信消息 Object[]objArray=(Object[])bundle.get("pdus"); //构建短信对象array,并依据收到的对象长度来创建array的大小 SmsMessage[]message=newSmsMessage[objArray.length]; for(inti=0;i<objArray.length;i++){ message[i]=SmsMessage.createFromPdu((byte[])objArray[i]); } //将送来的短信合并自定义信息于StringBuilder当中 for(SmsMessagecurrentMessage:message){ sb.append("短信来源"); //获得接收短信的电话号码 sb.append(currentMessage.getDisplayMessageBody()); sb.append("\n------短信内容------\n"); //获得短信的内容 sb.append(currentMessage.getDisplayMessageBody()); } IntentmainIntent=newIntent(context,SmsActivity.class); mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(mainIntent); Toast.makeText(context,sb.toString(),Toast.LENGTH_LONG).show(); } } } } main.xml文件编写代码: <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/textview" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="15dp" android:text="SMART收短信提示" /> </LinearLayout> 附件:http://down.51cto.com/data/2357601 本文转自 llb988 51CTO博客,原文链接:http://blog.51cto.com/llb988/498644,如需转载请自行联系原作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册