• [交流分享] Cat.1究竟是如何崛起的?中速率到底有什么用?
    2020年是5G商用元年。但是,如果我们在物联网行业内搞一场“2020年最热门通信技术”的评选,5G很可能无法独占冠军。因为,有一匹黑马,在这一年迅速崛起,吸引了整个行业的关注,也成为大众热议的话题。没错,这匹黑马,就是今天这篇文章的主角——LTE Cat.1。根据数据统计,2020年全球LTE Cat.1新增连接数为1500万个。乍一看并不是很多,但它的增长速度极快。行业资讯机构TSR预测,未来几年LTE Cat.1模组会保持3000万台以上的年均出货量。更有专家大胆预测,今年(2021年)就能达到5000万。LTE Cat.1为什么会迅速蹿红?它和其它蜂窝物联网技术相比,有哪些优势?我们现在常说的Cat.1和Cat.1bis,又有什么区别?别急,让我们从头开始说起。▉ LTE Cat.1的发展历程2009年3月,标准组织3GPP发布了Release 8 版本,正式把LTE推到了世人面前。当时,3GPP一共定义了5个终端类别,分别是LTE Cat.1、Cat.2、Cat.3、Cat.4、Cat.5。所谓的Cat,是英文单词“Category”的缩写,意思是“类别、种类”。之所以要搞出这么多UE Category(终端类别),是因为3GPP非常看好物联网市场的发展前景,希望设计出不同速率等级的终端类型,满足物联网不同落地场景的需求。从上图可以看出,LTE Cat.1的上行速率只有大约5Mbps,专门面向对速率要求不高的物联网应用。LTE Cat.1推出之后,并没有获得太多关注。当时,蜂窝物联网的使用场景还不多,用户比较陌生,市场也没有打开。几年后,随着LTE网络覆盖迅速形成规模,厂商们开始重新将视线放到了LTE Cat.1的身上。刚开始的时候,有手机终端厂商针对LTE Cat.1“简配”、低成本的特点,将其用于4G老人智能机。后来,蜂窝物联网应用场景快速增加,LTE Cat.1迎来了机会。2015年4月,第一代智能手表产品正式发售,拉开了价值千亿的可穿戴电子产品市场竞争帷幕。在激烈的市场争夺过程中,可穿戴设备厂商发现,LTE Cat.1并没有办法用于可穿戴设备。原因在于,Cat.1和传统LTE终端一样,设计有两根天线。而可穿戴设备对体积要求很高,必须小而又小,所以无法接受双天线。即便是强行塞入,分集接收效果也会大打折扣。当时,官方具备1Rx(单接收天线)接收规格的终端能力等级,只有Cat.0/Cat.M1/Cat.NB1。但是,这些技术最高只能实现1Mbps的极限吞吐速率,无法满足可穿戴场景的用户体验。于是,设计一种新的适用于可穿戴品类的单天线终端能力等级,就被提上了议事日程。2016年6月至2017年3月,3GPP RAN#73~#75标准全会就该单天线终端能力新等级做了讨论与定义。最终,在2017年3月9日,3GPP Release 13 LTE Cat.1bis核心部分正式冻结,LTE Cat.1bis诞生。除了天线数量之外,LTE Cat.1bis和LTE Cat.1并无太大区别,两者都是上行速率5Mbps,下行10Mbps,链路预算基本一致。这个“bis”,在英文里有“重复、两次、再来一次”的意思。LTE Cat.1bis,既能满足中速人联/物联品类的数据吞吐量需求,又能提供相比传统LTE更优的成本与更小的尺寸。更关键的是,它可以在现有4G接入网几乎零改造的前提下,进行快速部署,大幅削减落地成本。然而,如此完美的LTE Cat.1bis技术,在推出之后的前两年,不仅没有爆发,反而更加沉寂,几乎没有产生实质产业效益。这是为什么呢?原因大概有两个。一方面,是因为LTE Cat.1bis的标准化速度太慢。2018年9月,LTE Cat.1bis才完成合规认证所必要的测试部分(Testing part)冻结,根本没赶上2017年7月的全球首款蜂窝版可穿戴产品上市这波行情。另一方面,R13 Cat.1bis推出之后,业界根本没来得及准备合适的芯片平台。没有芯片,咋推出产品?阴差阳错之下,Cat.1bis最终缺席了原本属于它的可穿戴/中速物联广阔舞台。▉ Cat.1bis的逆袭到了2019年底,情况发生了根本性的变化。之前没有的终端芯片平台,现在有了!2019年11月16日,在第7届中国移动全球合作伙伴大会上,紫光展锐重磅发布了新一代物联网芯片平台——展锐8910DM,这是全球首颗LTE Cat.1bis物联网芯片平台。从功能上来看,展锐8910DM又不仅是一颗LTE Cat.1bis芯片。它采用28nm工艺,具备显著的低功耗优势,支持LTE Cat.1bis和GSM双模,上下行速率分别是5Mbps和10Mbps,拥有高集成度,同时集成了蓝牙通讯和Wi-Fi室内定位,可实现更稳定的连接,支持VoLTE。展锐8910DM的推出,解决了用户在物联网连接中通信、运算、存储、定位等多方面的需求和痛点,引领了行业标准制定和行业生态构建,填补了低功耗窄带物联网与传统宽带物联网之间的蜂窝通信芯片方案空白。芯片平台诞生之后,外部环境也发生了微妙变化,为LTE Cat.1bis的爆发创造了非常有利的条件。什么变化?当然是5G的商用。5G商用,意味着运营商又多了一张网络需要维护,势必增加其网络运维压力。为了减少压力,集中资源建设新网络,运营商会加速2G/3G的退网。2G/3G想要顺利退网,就必须有合适的替代技术,承接海量的中低速物联网终端。NB-IoT是窄带物联网,速度极低,仅可承载部分2G网络物联网终端。“中速率、语音通话、移动连接”的业务需求,自然而然就落在了LTE Cat.1bis 的身上。2020年5月,工信部发布了《关于深入推进移动物联网全面发展的通知》,其中明确指出:“推动2G/3G物联网业务迁移转网,引导新增物联网终端不再使用2G/3G网络,推动存量2G/3G物联网业务向NB-IoT/4G(含Cat.1)/5G网络迁移,建立协同发展的移动物联网综合生态体系。”针对这个协同发展的体系,行业已经形成了普遍共识,那就是物联网连接的“631”结构。所谓“631”,即指:60%的连接通过低速率网络实现,30%的连接通过中速率网络实现,10%的连接通过高速率网络实现。“631”结构LTE Cat.1bis,主要承载的是30%的中速率物联网连接领域。相比于NB-IoT,LTE Cat.1bis速率更高,可以支持标清摄像头、广告屏等应用,也多了移动性的,可以支持共享单车、物流追踪等对移动性有要求的应用。它还支持基本的语音业务,可以用于集群对讲、电话手表等业务。从技术替代趋势来看,NB-IoT将实现对80%以上2G终端的替代,而绝大部分的3G和少部分的2G,将迁移到Cat.1。▉ Cat.1bis的技术革新为了更好地完成自身使命,LTE Cat.1bis一直在进行着技术革新和功能演进。我们还是以紫光展锐的8910DM芯片平台为例。2020年11月,紫光展锐联合中国联通,基于采用8910DM芯片平台的联通雁飞Cat1模组,开展了业界首次Cat.1bis PSM低功耗特性现网规模测试。此前,人们一直以为eDRX/PSM是NB-IoT/eMTC独有的特性。这次测试表明,紫光展锐的Cat.1bis芯片也能够支持扩展非连续接收eDRX和深度睡眠PSM。如此一来,Cat.1bis的功耗表现实现从传统的mA级升级到uA级,大大拓宽了应用领域,可以满足例如智能表计、智能门锁、烟感报警等使用电池供电、对功耗要求苛刻的场景。在覆盖增强方面,8910DM芯片平台也有突破。它已成功实现对R13 coverage enhancement特性的支持,可提供最高15dB的增益。这将非常有利于将Cat.1bis部署于地下车库、地下室、密集城区阴影区等覆盖困难的场所,扩大应用领域。除了性能进一步提升之外,紫光展锐8910DM芯片平台还根据用户使用场景,进行了很多场景专属优化。举例来说,8910DM芯片原本就已支持BLE(蓝牙低功耗)功能,可进行近程设备升级维护和参数配置。如此,8910DM又新增支持了A2DP和HFP等蓝牙媒体协议,让物联网设备也能够进行音乐播放。比如,可以让支付云喇叭同时“变身”成蓝牙音箱、让公网对讲机还能连接蓝牙耳机、让共享两轮出行的路上也能有音乐陪伴。再举个例子,基于8910DM作为主芯片平台的公网对讲机方案,能够完全满足运营商对于公网对讲产品的要求。展锐针对公网对讲机的实网时延和通话音质,进行了大量优化:网络方面,包括支持双卡双待以及实现IP数据包在4G/2G实网下的时延优化;音质方面,通过充分利用芯片的语音处理能力, 对于噪音/回声/啸叫等对讲常见问题进行专项处理。上述这一系列的提升和优化,充分说明了LTE Cat.1bis可以实现功耗、成本、覆盖、功能方面的更完美平衡,给用户带来极致的使用体验。当然,这背后也离不开紫光展锐这样的民族芯片企业,在自主创新技术方面长期坚持不懈的投入。基于这些投入,紫光展锐已经成为国内集成电路设计产业的龙头,全球少数全面掌握2G/3G/4G/5G、Wi-Fi、蓝牙、电视调频、卫星通信等全场景通信技术的企业之一。根据数据显示,紫光展锐目前拥有近5000名员工,其中90%是研发人员,在全球拥有17个技术研发中心。目前,紫光展锐的Cat.1芯片已经实现千万级出货,全国市场占有率超过70%。数十款搭载展锐8910DM芯片的Cat.1bis模组,正在广泛应用于共享经济、金融支付、公网对讲、能源、工业控制等行业场景。 ▉ 结语2021年,LTE Cat.1bis还将继续火热下去。针对LTE Cat.1bis的生态,将会变得更加成熟。相关的物联网应用,也会越来越多地出现在我们身边。我们有理由相信,随着蜂窝物联网终端连接数的不断增加,“万物智联”的时代将加速向我们走来。整个社会的运作模式将发生根本性的变化,我们的工作效率和生活质量也将迎来难以想象的飞跃。期待这一天的早日到来。翻滚吧,LTE Cat.1bis!
  • [专题汇总] Android 安装包优化
    SVG 全称 Scalable Vector Graphics , 可缩放矢量图 ; 矢量图不会随着图像缩放 , 出现图像质量降低的情况 ;png , jpeg 等位图会随着图像缩放 , 出现模糊的情况 ;Android 中使用 SVG 矢量图 , 能极大的减少占用空间的大小 ;应用中使用的小图标 , 一般都使用 SVG 格式 ;Android 中生成 Vector 矢量图资源但是在 Android 中 , 不能直接使用标准的 SVG 文件 , 使用 Vector Assets 实现对 SVG 图片格式的支持 , Vector 矢量图也是 XML 文件 , 根节点必须是 <vector> , 并且内容格式也有一定的不同 ;SVG 图片的根节点是 <svg> ;Vector 资源的根节点是 <vector> ;在 Android Studio 中 , 右键点击 res 资源目录 , 选择 " New / Vector Asset " 选项 ,
  • [技术干货] HBuilder使用夜神模拟器调试Android应用
    打开HBuilder——工具——选项——HBuilder 将第三方安卓模拟器端口号改为62001即可如果是海马的话 改为26944
  • [交流分享] Android手机4G网络设置ipv6
    我的卡是联通的,所以下面截图也是联通的,移动和电信的卡类似;1.进入目录:设置--移动网络--接入点名称(APN);2.点击默认的连接项,进入详情页,如果‘APN协议’可以更改,则直接修改为IPV6,返回保存即可(注意不要修改APN漫游协议);3.如果‘APN协议’不可以更改,则返回到APN首页,新建一个APN Qq(名字可以随便起),其他的配置项和默认的沃宽带用户连接互联网保持一致,但要设置‘APN协议’为IPV6(注意要设置APN漫游协议为IPV4/IPV6);4.保存设置,连接到新建的APN;  浏览器输入test-ipv6.com,测试网络是否连接到ipv6;
  • [技术干货] 【转载】Android手机4G网络设置ipv6
    我的卡是联通的,所以下面截图也是联通的,移动和电信的卡类似;1.进入目录:设置--移动网络--接入点名称(APN);2.点击默认的连接项,进入详情页,如果‘APN协议’可以更改,则直接修改为IPV6,返回保存即可(注意不要修改APN**协议);3.如果‘APN协议’不可以更改,则返回到APN首页,新建一个APN Qq(名字可以随便起),其他的配置项和默认的沃宽带用户连接互联网保持一致,但要设置‘APN协议’为IPV6(注意要设置APN**协议为IPV4/IPV6);4.保存设置,连接到新建的APN;  浏览器输入test-ipv6.com,测试网络是否连接到ipv6;————————————————版权声明:本文为CSDN博主「无聊看星星」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/weixin_42734141/article/details/116044389
  • [技术干货] Android和IOS两个系统的手机APP安装测试
      安装测试  软件在不同操作系统(Android系统和IOS系统)上是否正常安装。  软件在不同版本的操作系统(如Android 5.0/Android 6.0/Android 7.0/Android8.0和iOS 9.0/iOS 10.0/iOS 11.0/iOS 12.0)上是否正常安装。  软件在不同的品牌手机(华为/三星/OPPO/VIVO等其他品牌手机)上是否正常安装。  卸载旧版本再安装(这个操作可以排插新版本的安装包是否丢失库,如果是覆盖安装的话会继续依赖旧库,导致问题发现不了)。  覆盖安装是否正常。  降级安装是否能成功。  磁盘空间不足时,是否可以正常安装,安装的现象是什么。  安装过程中是否可以手动取消。  安装过程中突然手机关机怎么处理。  卸载测试  按照手机自身的卸载流程卸载是否能正常卸载。  使用adb命令卸载是否可以卸载。  卸载过程中有没有异常提示。  卸载过程中突然关机是否卸载成功。  界面测试(UI)。  界面上的布局是否按照需求上设计。  界面内容是否符合文档需求,文字是否有乱码或者翻译问题。  图片、动画、边框、颜色、字体、背景、按钮、目录、菜单、弹框、列表等…  软件logo,颜色,名称。
  • [技术干货] 基于Android SQLite的升级详解
    做Android应用,不可避免的会与SQLite打交道。随着应用的不断升级,原有的数据库结构可能已经不再适应新的功能,这时候,就需要对SQLite数据库的结构进行升级了。SQLite提供了ALTER TABLE命令,允许用户重命名或添加新的字段到已有表中,但是不能从表中删除字段。并且只能在表的末尾添加字段,比如,为 Subscription添加两个字段:ALTER TABLE Subscription ADD COLUMN Activation BLOB;ALTER TABLE Subscription ADD COLUMN Key BLOB;另外,如果遇到复杂的修改操作,比如在修改的同时,需要进行数据的转移,那么可以采取在一个事务中执行如下语句来实现修改表的需求。1. 将表名改为临时表ALTER TABLE Subscription RENAME TO __temp__Subscription;2. 创建新表CREATE TABLE Subscription (OrderId VARCHAR(32) PRIMARY KEY ,UserName VARCHAR(32) NOT NULL ,ProductId VARCHAR(16) NOT NULL);3. 导入数据INSERT INTO Subscription SELECT OrderId, “”, ProductId FROM __temp__Subscription;4. 删除临时表DROP TABLE __temp__Subscription;通过以上四个步骤,就可以完成旧数据库结构向新数据库结构的迁移,并且其中还可以保证数据不会应为升级而流失。
  • [热门活动] 活动已结束,获奖名单已公布【HDC.Hi 鲲鹏】参与鲲鹏MVP分享活动,赢超薄有线键盘、华为手环和码豆等好礼
     什么是鲲鹏MVP? 鲲鹏最有价值专家,简称MVP(Most Valuable Professional),是专注于帮助开发者了解和使用鲲鹏的行业意见领袖和技术专家,是华为公司授予行业意见领袖和技术专业人士的一个奖项,以嘉奖有影响力和特殊贡献的专家,并赋予特殊的权益和使命。 MVP能享受哪些权益? 参与方式 1、分享以下海报至朋友圈,且至少存在2小时后,在本活动帖下方回复分享截图,即可获得200码豆,并且获得抽奖活动的资格;2、凡成功分享海报的用户,即可参与抽奖,一等奖为华为超薄有线键盘,2个;二等奖为华为手环 4e活力款,3个。 活动奖品  什么是码豆?会员中心入口:https://devcloud.huaweicloud.com/bonususer/home 码豆奖励活动规则:1)码豆可在码豆会员中心兑换实物礼品;2)码豆只能用于会员中心的礼品兑换,不得转让,具体规则请到会员中心阅读“码豆规则”;3)为保证码豆成功发放,如果修改过账号名还请向工作人员提供修改前后的账号名。  活动时间 2021年4月6日—2021年5月5日 活动规则 1)请务必使用个人账号参与活动(IAM、企业账号等账号参与无效);2)所有获得华为奖品的用户,请于获奖后3个工作日内完成实名认证,否则视为放弃奖励;3)本次活动一个实名认证账号只能对应一个收件人,如同一账号填写多个不同收件人,不予发放奖励;4)本次活动,码豆预计于2021年5月15日前完成发放,实物奖品预计于2021年6月5日前完成发放,发放时间根据实际情况动态调整,如有延期敬请见谅;5)本活动最终解释权归华为云所有。邀请好友助力赢HUAWEI Mate 30E Pro 5G等好礼>>>点击了解详情 Hi 鲲鹏 HDC 开发者缤纷嘉年华,丰厚好礼等你来拿!尊敬的用户们:由于需采购的奖品类别较多,部分奖品暂时缺货,导致采购延迟十分抱歉。目前华为商城有货的奖品正在采购中,请大家耐心等待一下,谢谢谅解!以下是获奖用户名单公示,请获得实物奖品的用户于5月14日前反馈姓名、手机号、邮箱、收货地址给帖主,逾期未反馈视为自动放弃奖品:)一等奖-华为超薄有线键盘二等奖-华为手环 4e活力款holo.yhying1212林小淦蜡笔不辣考过IE励志当攻城狮昵称所得码豆昵称所得码豆小强鼓掌200Drawn-rays200yzq18941596181200问道200yzq13516078375200ruochen200zhengyong134200user_beifeng200陪姐200linghz666200Solo丶鲲鹏200holo.yh200十年树木200追逐枫叶的猫200蜡笔不辣200hw26536804200Mr.兜兜200林小淦200khg305387543200帅气的我200suncker200yizhangl200Devil-yao200nukinsan200franco52576200lsj9527200王亦臻200416182384200爱吃鱼的靖哥哥200abcabc200考过IE励志当攻城狮200仙女本仙200千江有水千江月200hw1993200ying1212200shao1112200厄尔让我2200tanshaotang200hw62056453200
  • [技术干货] Android 实现九宫格抽奖功能
    public class NineLuckPan extends View { private Paint mPaint; private ArrayList<RectF> mRects;//存储矩形的集合 private float mStrokWidth = 5;//矩形的描边宽度 private int mRectSize;//矩形的宽和高(矩形为正方形) private int[] mItemColor = {Color.GREEN, Color.YELLOW};//矩形的颜色  public NineLuckPan(Context context) {  this(context, null); }  public NineLuckPan(Context context, @Nullable AttributeSet attrs) {  this(context, attrs, 0); }  public NineLuckPan(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  init(); }  /**  * 初始化数据  */ private void init() {  mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  mPaint.setStyle(Paint.Style.FILL);  mPaint.setStrokeWidth(mStrokWidth);  mRects = new ArrayList<>(); }  @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {  super.onSizeChanged(w, h, oldw, oldh);  mRectSize = Math.min(w, h) / 3;//获取矩形的宽和高  mRects.clear();//当控件大小改变的时候清空数据  initRect();//重新加载矩形数据 }  /**  * 加载矩形数据  */ private void initRect() {  //加载前三个矩形  for (int x = 0; x < 3; x++) {   float left = x * mRectSize;   float top = 0;   float right = (x + 1) * mRectSize;   float bottom = mRectSize;   RectF rectF = new RectF(left, top, right, bottom);   mRects.add(rectF);  }  //加载第四个  mRects.add(new RectF(getWidth() - mRectSize, mRectSize, getWidth(), mRectSize * 2));  //加载第五~七个  for (int y = 3; y > 0; y--) {   float left = getWidth() - (4 - y) * mRectSize;   float top = mRectSize * 2;   float right = (y - 3) * mRectSize + getWidth();   float bottom = mRectSize * 3;   RectF rectF = new RectF(left, top, right, bottom);   mRects.add(rectF);  }  //加载第八个  mRects.add(new RectF(0, mRectSize, mRectSize, mRectSize * 2));  //加载第九个  mRects.add(new RectF(mRectSize, mRectSize, mRectSize * 2, mRectSize * 2)); }  @Override protected void onDraw(Canvas canvas) {  super.onDraw(canvas);  drawRects(canvas); }  /**  * 画矩形  *  * @param canvas  */ private void drawRects(Canvas canvas) {  for (int x = 0; x < mRects.size(); x++) {   RectF rectF = mRects.get(x);   if (x == 8) {//中心的矩形背景为白色    mPaint.setColor(Color.WHITE);    canvas.drawRect(rectF, mPaint);   } else {    mPaint.setColor(mItemColor[x % 2]);    canvas.drawRect(rectF, mPaint);   }  } }}
  • [技术干货] 你的测试用例中,是否包含App前后台切换
    你的测试用例中,是否包含App前后台切换App前后台切换是我们平时常用的一个操作,比如:按手机的home键将应用置于后台、直接按手机电源键关闭屏幕或者通过最近打开的应用列表切换应用等,由此,我们可以得出结论:当app置于前台时,它的页面对我们是可见的;当app置于后台时,它的页面对我们是不可见的。  无论对于Android还是IOS,app前后台切换的流程都很长,因为牵扯到应用生命周期的管理,因此在测试过程中,可以帮我们发现一些意外的惊喜。不知道在你的App测试用例中是否包含前后台切换?如果没有,那从现在开始,你一定要将它补充到测试用例中。  这篇文章,会带着大家了解Android和IOS在前后台切换过程中,都经历了什么。这样当你在测试过程中,碰到相关问题时,也能有章可循。  Android前后台切换原理  早期的Android只有Activity用来展示页面元素,直到2011年Android3.0推出了Fragment的概念,不过Fragment并没有立即被用起来,大部分的开发者还是用Activity写Android页面,个人感觉是到Android4.x之后,Fragment才更多的运用到工作中。不过Fragment并不能单独的存在,其必须依赖在某一个Activity上,所以到后来GitHub上出现了好多Activity+Fragment的基础框架,其核心思想是:一个BaseActivity+多个Fragment。BaseActivity主要用于管理Fragment的生命周期,而Fragment用于实现不同的页面。前后台切换思路整理  对于没有任何移动端开发经验的人来说,Android和IOS应该也不大理解其中的原理。所以我根据自己的经验,帮大家整理一些前后台切换的测试的思路及出发点,供大家参考:  因为有重复调用同一个方法的可能,所以开发可能会用到标志位(用于标识是否是第一次调用)等,因此可以验证如下点:  界面上的逻辑是否正确,比如:数据不一致。  界面展示是否正确,比如:某些按钮不应该展示,却展示了。  因为有可能新创建对象,所以需要关注是否有内存泄漏存在。  是否会造成异常的网络请求,比如重复请求同一接口。  在app将要置于后台时,会保存当前界面上的数据,等到app再次回到前台时,重新渲染:  验证前后台切换后,界面数据是否被清空。  另外界面数据展示是否正常。  其他  是否会出现crash。  是否会造成app的专项数据异常,比如:cpu、耗电量等。  总结  软件测试,其实一定程度上就是用探索性的思路,挖掘更不容易出现的"惊喜",因此,我觉得"App前后台"切换绝对是一个不错的探索思路。
  • [技术干货] Android批量插入数据到SQLite数据库的方法
    Android中在sqlite插入数据的时候默认一条语句就是一个事务,因此如果存在上万条数据插入的话,那就需要执行上万次插入操作,操作速度可想而知。因此在Android中插入数据时,使用批量插入的方式可以大大提高插入速度。有时需要把一些数据内置到应用中,常用的有以下几种方式:1、使用db.execSQL(sql)这里是把要插入的数据拼接成可执行的sql语句,然后调用db.execSQL(sql)方法执行插入。public void inertOrUpdateDateBatch(List<String> sqls) { SQLiteDatabase db = getWritableDatabase(); db.beginTransaction(); try { for (String sql : sqls) { db.execSQL(sql); } // 设置事务标志为成功,当结束事务时就会提交事务 db.setTransactionSuccessful(); } catch (Exception e) { e.printStackTrace(); } finally { // 结束事务 db.endTransaction(); db.close(); } } 2、使用db.insert("table_name", null, contentValues)这里是把要插入的数据封装到ContentValues类中,然后调用db.insert()方法执行插入。db.beginTransaction(); // 手动设置开始事务 for (ContentValues v : list) { db.insert("bus_line_station", null, v); } db.setTransactionSuccessful(); // 设置事务处理成功,不设置会自动回滚不提交 db.endTransaction(); // 处理完成 db.close() 3、使用InsertHelper类这个类在API 17中已经被废弃了InsertHelper ih = new InsertHelper(db, "bus_line_station"); db.beginTransaction(); final int directColumnIndex = ih.getColumnIndex("direct"); final int lineNameColumnIndex = ih.getColumnIndex("line_name"); final int snoColumnIndex = ih.getColumnIndex("sno"); final int stationNameColumnIndex = ih.getColumnIndex("station_name"); try { for (Station s : busLines) { ih.prepareForInsert(); ih.bind(directColumnIndex, s.direct); ih.bind(lineNameColumnIndex, s.lineName); ih.bind(snoColumnIndex, s.sno); ih.bind(stationNameColumnIndex, s.stationName); ih.execute(); } db.setTransactionSuccessful(); } finally { ih.close(); db.endTransaction(); db.close(); } 4、使用SQLiteStatement查看InsertHelper时,官方文档提示改类已经废弃,请使用SQLiteStatementString sql = "insert into bus_line_station(direct,line_name,sno,station_name) values(?,?,?,?)"; SQLiteStatement stat = db.compileStatement(sql); db.beginTransaction(); for (Station line : busLines) { stat.bindLong(1, line.direct); stat.bindString(2, line.lineName); stat.bindLong(3, line.sno); stat.bindString(4, line.stationName); stat.executeInsert(); } db.setTransactionSuccessful(); db.endTransaction(); db.close(); 第三种方法需要的时间最短,鉴于该类已经在API17中废弃,所以第四种方法应该是最优的方法。
  • [技术干货] Android(twenty-one)
    网络编程Android应用作为一个客户端程序绝大部分都是需要进行网络请求和访问的,而http通信是一种比较常见并常用的通信方式。在Android中原生http网络编程中有两种实现方式,一种是使用HttpURLConnection,另一种就是使用HttpClient。现在使用更广泛的是HttpURLConnection这两种实现方式的大体过程都是:Android客户端向服务器发出请求。服务端接收请求并响应。服务端返回数据给客户端。在Http通信中有POST和GET两种方式,其不同之处在于GET方式可以获得静态页面,同时可以将请求参数放在URL字符串后面,传递给服务器;而POST方式的参数则是放在Http请求中的。因此,无论你是用哪一种HTTP实现方式都需要明确所使用的请求方式。ttpURLConnection根据使用目的不同,在具体使用时会稍有区别。从Internet获取网页,即向URL发送请求,将网页以流的形式读回本地。从Internet获取文件,即利用HttpURLConnection对象从网络中获取文件数据。向Internet发送请求参数,即向服务器传递参数,即向服务器传递参数向Internet传送XML数据。(使用HTTP的的方式传输文件,一般文件大小在5M一下,HTTP通信方式不适合传输大文件,对大文件的传输最好使用Socket通信方式,以保证程序的稳定性。)
  • [行业资讯] 鸿蒙系统志在5G时代超越安卓,IoT生态发展缓慢亟待解决
    (记者 陈洲)在2020年12月16日鸿蒙OS手机开发者Beta版发布会上,华为消费者业务软件部总裁王成录激动地说:“今天是中国所有移动互联网产业从业人员应该记住的一个日子。”这句话在近日多个媒体的报道中陆续出现,因为这是个划时代的超越。正如王成录曾多次强调的:鸿蒙OS不是为了替代安卓,而是要超越安卓!打造5G万物互联时代的下一代操作系统。可是,当前存在IoT生态发展缓慢的问题,最核心的原因在于操作系统的高度碎片化。即使是同一家企业生产的 IoT 设备之间,都存在连接、配网等障碍,因此,5G时代,打造IoT设备之间的系统互通,除有运营商提供的良好5G网络支撑外,还需要设备厂商、APP开发商的通力合作。鸿蒙OS旨在打造5G系统并超越安卓近日,新浪科技一篇题为《华为,迈出了摒弃安卓的第一步》的文章可谓振奋国人心。这就要从2019年华为对外发布鸿蒙系统说起,华为消费者业务软件部总裁王成录曾多次强调的:开发鸿蒙OS的目的,并不是为了替代安卓,而是要超越安卓!这是一款面向未来,打造5G万物互联时代的下一代操作系统。在12月16日鸿蒙OS手机开发者Beta版发布会上他再次激动地让全国所有移动互联网产业从业人员记住这个日子。相关资料显示,发布会现场的演示中,鸿蒙系统确实推出了部分安卓并未实现的功能,与安卓系统不同的是,鸿蒙系统不仅限于搭载手机,而是跨越到手机+IoT设备,让智能设备实现功能的交互。2020世界物联网大会组委会主席、科技部原秘书长石定寰曾指出,中国是物联网应用实践和创新开发最多的国家,占到了全球物联网产值的1/4左右,预计2020年的年产值超2万亿人民币。因此,给IoT设备赋予“灵魂”,就显得尤为关键了。在这方面,安卓系统确实已经落后了。5G万物互联操作系统让科幻成为现实喜欢科幻片的朋友一定会对影片中多场景的触屏操作记忆犹新,有句老话说得好:科幻来自未来,科幻片中的画面在未来某一时刻终会实现。5G时代的到来,正在让科幻片中的高科技镜头成为现实。鸿蒙OS在泛终端社交购物上的表现,就较为“科幻”。京东App在鸿蒙系统中的版本,就可以解决当前诸多消费者的购物痛点。据京东零售产品总监王志强介绍,与安卓版本不同的是,鸿蒙版本的京东App让消费者不再需要频繁切换产品页面,可以将产品详情页直接流转至平板上,手机和平板可以同时对比不同的商品。另外,在直播购物和拼单场景下,鸿蒙版本可以将直播流转至智慧屏上,好友或者家人可以共享屏幕讨论商品,甚至共享购物车一起拼单凑满减,并且各自生成订单,各自结算付款。再看看移动办公方面,在鸿蒙OS搭载的硬件上,甚至出现了传说中的“神来之笔”。据科大讯飞消费者事业群听见科技CTO苏文畅介绍,科大讯飞的录音笔在搭载鸿蒙OS之后,手机可在无App情况下一碰即用,触碰后还可以将录音文件快传至手机,甚至可以将手机端的实时转写流转至智慧屏端实时显示。操作系统高度碎片化制约IoT生态的发展分析人士称,其实从2018年开始,手机APP就不再增长,甚至在近两年走向下降,这意味着基于手机的生态已经来到了一个临界点,据王成录判断,未来必定是IoT的时代。数据显示,当前中国的5G用户数已接近2亿,占全球比重的85%。可见,我国的5G用户基础已经比较牢固。然而,我们都不难发现,当前的IoT生态发展进度缓慢,大家一直在提5G万物互联,可实际上可称得上“经典”的应用和场景并不多。这之中最为核心的问题就在于操作系统不统一,呈现高度碎片化趋势,即使是同一家企业生产的IoT设备之间,都存在连接、配网等障碍。在三大运营商的共同努力下,我国已经建成世界上规模最大、覆盖面最广的5G网络,然而,现在面临的问题是空有“管道”,缺乏流通的“精油”。在5G万物互联时代,打造IoT设备之间的系统互通、信息交互、数据共享等,除有运营商提供的良好5G网络支撑外,更需要设备厂商、APP开发商的通力合作,统一系统、统一开发APP的标准、统一产品验收标准,不能让IoT设备、IoT产品的设计制作者徒劳无功,更不能让消费者感觉万物互联还在科幻片里。
  • [经验交流] 浅谈 UNIX、Linux、IOS、Android、鸿蒙之间的关系
    Unix, 简化形成了Linux,Linux则是Android的内核,而苹果则是使用unix系统作为ios和macos的内核。几个系统出现的时间1969年,贝尔实验室的研究员肯•汤普森,编写了一款计算机游戏Space Travel,先后在多个系统上运行,然而效果不理想,所以决定自己开发操作系统,就这样UNIX诞生了。贝尔实验室存在的时候就是永久的神,最后却因为反垄断被拆分,也预示着一个贝尔实验室时代的结束,当真让人叹息。Linux系统的诞生1991年,李纳斯•托瓦兹大学读书时,为了个人爱好编写了Linux,相当于迷你版的UNIX。随后,李纳斯•托瓦兹公开了Linux源代码,邀请他人一块完善Linux。据说最后李纳斯•托瓦兹所写的代码只占Linux源代码的2%,但他的名字将会永远的留在互联网发展史上。基于unix系统,苹果ios诞生ios是苹果公司最早于2007年1月9日的Macworld大会上公布这个系统,最初是设计给iPhone使用的,后来陆续套用到iPod touch、iPad上。iOS与苹果的macOS操作系统一样,属于类Unix的商业操作系统。基于linux系统,安卓诞生2007年11月,Google与84家硬件制造商、软件开发商及电信营运商组建开放手机联盟共同研发改良Android系统。随后Google以Apache开源许可证的授权方式,安卓是一种基于Linux内核(不包含GNU组件)的自由及开放源代码的操作系统。最后不得不说还有华为的鸿蒙系统,其是和 Android 并列的,也是出自 Linux 内核。总    结因此我们就很清晰的理出了一条线路那就是Unix, 简化形成了Linux,Linux则是安卓的内核,而苹果则是使用unix系统作为ios和macos的内核。
  • [应用实践] 【转载】实现一个图像分类应用,部署到端侧安卓APP
    实现一个图像分类应用实现一个图像分类应用示例程序结构配置MindSpore Lite依赖项下载及部署模型文件编写端侧推理代码运行依赖构建与运行概述选择模型转换模型部署应用示例程序详细说明概述我们推荐你从端侧Android图像分类demo入手,了解MindSpore Lite应用工程的构建、依赖项配置以及相关API的使用。本教程基于MindSpore团队提供的Android“端侧图像分类”示例程序,演示了端侧部署的流程。选择图像分类模型。将模型转换成MindSpore Lite模型格式。在端侧使用MindSpore Lite推理模型。详细说明如何在端侧利用MindSpore Lite C++ API(Android JNI)和MindSpore Lite图像分类模型完成端侧推理,实现对设备摄像头捕获的内容进行分类,并在APP图像预览界面中,显示出最可能的分类结果。你可以在这里找到Android图像分类模型和示例代码。选择模型MindSpore团队提供了一系列预置终端模型,你可以在应用程序中使用这些预置的终端模型。MindSpore Model Zoo中图像分类模型可在此下载。 同时,你也可以使用预置模型做迁移学习,以实现自己的图像分类任务。转换模型如果预置模型已经满足你要求,请跳过本章节。 如果你需要对MindSpore提供的模型进行重训,重训完成后,需要将模型导出为.mindir格式。然后使用MindSpore Lite模型转换工具将.mindir模型转换成.ms格式。以mobilenetv2模型为例,如下脚本将其转换为MindSpore Lite模型用于端侧推理。./converter_lite --fmk=MINDIR --modelFile=mobilenetv2.mindir --outputFile=mobilenetv2.ms部署应用接下来介绍如何构建和执行mindspore Lite端侧图像分类任务。运行依赖Android Studio >= 3.2 (推荐4.0以上版本)NDK 21.3CMake 3.10.2Android SDK >= 26JDK >= 1.8构建与运行在Android Studio中加载本示例源码,并安装相应的SDK(指定SDK版本后,由Android Studio自动安装)。启动Android Studio后,点击File->Settings->System Settings->Android SDK,勾选相应的SDK。如下图所示,勾选后,点击OK,Android Studio即可自动安装SDK。(可选)若安装时出现NDK版本问题,可手动下载相应的NDK版本(本示例代码使用的NDK版本为21.3),并在Project Structure的Android NDK location设置中指定NDK的位置。连接Android设备,运行图像分类应用程序。通过USB连接Android设备调试,点击Run 'app'即可在你的设备上运行本示例项目。Android Studio连接设备调试操作,可参考https://developer.android.com/studio/run/device?hl=zh-cn。手机需开启“USB调试模式”,Android Studio才能识别到手机。 华为手机一般在设置->系统和更新->开发人员选项->USB调试中打开“USB调试模式”。在Android设备上,点击“继续安装”,安装完即可查看到设备摄像头捕获的内容和推理结果。识别结果如下图所示。示例程序详细说明本端侧图像分类Android示例程序分为JAVA层和JNI层,其中,JAVA层主要通过Android Camera 2 API实现摄像头获取图像帧,以及相应的图像处理等功能;JNI层在Runtime中完成模型推理的过程。此处详细说明示例程序的JNI层实现,JAVA层运用Android Camera 2 API实现开启设备摄像头以及图像帧处理等功能,需读者具备一定的Android开发基础知识。示例程序结构app├── src/main│   ├── assets # 资源文件|   |   └── mobilenetv2.ms # 存放模型文件│   |│   ├── cpp # 模型加载和预测主要逻辑封装类|   |   ├── ..|   |   ├── mindspore-lite-1.0.0-minddata-arm64-cpu # MindSpore Lite版本|   |   ├── MindSporeNetnative.cpp # MindSpore调用相关的JNI方法│   |   └── MindSporeNetnative.h # 头文件|   |   └── MsNetWork.cpp # MindSpore接口封装│   |│   ├── java # java层应用代码│   │   └── com.mindspore.himindsporedemo│   │       ├── gallery.classify # 图像处理及MindSpore JNI调用相关实现│   │       │   └── ...│   │       └── widget # 开启摄像头及绘制相关实现│   │           └── ...│   │   │   ├── res # 存放Android相关的资源文件│   └── AndroidManifest.xml # Android配置文件│├── CMakeList.txt # cmake编译入口文件│├── build.gradle # 其他Android配置文件├── download.gradle # 工程依赖文件下载└── ...配置MindSpore Lite依赖项Android JNI层调用MindSpore C++ API时,需要相关库文件支持。可通过MindSpore Lite源码编译生成mindspore-lite-{version}-minddata-{os}-{device}.tar.gz库文件包并解压缩(包含libmindspore-lite.so库文件和相关头文件),在本例中需使用生成带图像预处理模块的编译命令。version:输出件版本号,与所编译的分支代码对应的版本一致。device:当前分为cpu(内置CPU算子)和gpu(内置CPU和GPU算子)。os:输出件应部署的操作系统。本示例中,build过程由app/download.gradle文件自动下载MindSpore Lite版本文件,并放置在app/src/main/cpp/目录下。注: 若自动下载失败,请手动下载相关库文件,解压后将其放在对应位置:mindspore-lite-1.0.0-minddata-arm64-cpu.tar.gz 下载链接android{    defaultConfig{        externalNativeBuild{            cmake{                arguments "-DANDROID_STL=c++_shared"            }        }        ndk{             abiFilters'armeabi-v7a', 'arm64-v8a'          }    }}在app/CMakeLists.txt文件中建立.so库文件链接,如下所示。# ============== Set MindSpore Dependencies. =============include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp)include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/third_party/flatbuffers/include)include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION})include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/include)include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/include/ir/dtype)include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/include/schema)add_library(mindspore-lite SHARED IMPORTED )add_library(minddata-lite SHARED IMPORTED )set_target_properties(mindspore-lite PROPERTIES IMPORTED_LOCATION        ${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/lib/libmindspore-lite.so)set_target_properties(minddata-lite PROPERTIES IMPORTED_LOCATION        ${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/lib/libminddata-lite.so)# --------------- MindSpore Lite set End. --------------------# Link target library.       target_link_libraries(    ...     # --- mindspore ---        minddata-lite        mindspore-lite    ...)下载及部署模型文件从MindSpore Model Hub中下载模型文件,本示例程序中使用的终端图像分类模型文件为mobilenetv2.ms,同样通过app/download.gradle脚本在APP构建时自动下载,并放置在app/src/main/assets工程目录下。注:若下载失败请手工下载模型文件,mobilenetv2.ms 下载链接编写端侧推理代码在JNI层调用MindSpore Lite C++ API实现端测推理。推理代码流程如下,完整代码请参见src/cpp/MindSporeNetnative.cpp。加载MindSpore Lite模型文件,构建上下文、会话以及用于推理的计算图。加载模型文件:创建并配置用于模型推理的上下文// Buffer is the model data passed in by the Java layerjlong bufferLen = env->GetDirectBufferCapacity(buffer);char *modelBuffer = CreateLocalModelBuffer(env, buffer);创建会话void **labelEnv = new void *;MSNetWork *labelNet = new MSNetWork;*labelEnv = labelNet;// Create context.mindspore::lite::Context *context = new mindspore::lite::Context;context->thread_num_ = num_thread;// Create the mindspore session.labelNet->CreateSessionMS(modelBuffer, bufferLen, context);delete (context);加载模型文件并构建用于推理的计算图void MSNetWork::CreateSessionMS(char* modelBuffer, size_t bufferLen, std::string name, mindspore::lite::Context* ctx){    CreateSession(modelBuffer, bufferLen, ctx);      session = mindspore::session::LiteSession::CreateSession(ctx);    auto model = mindspore::lite::Model::Import(modelBuffer, bufferLen);    int ret = session->CompileGraph(model);}将输入图片转换为传入MindSpore模型的Tensor格式。将待检测图片数据转换为输入MindSpore模型的Tensor。// Convert the Bitmap image passed in from the JAVA layer to Mat for OpenCV processing BitmapToMat(env, srcBitmap, matImageSrc);// Processing such as zooming the picture size.matImgPreprocessed = PreProcessImageData(matImageSrc);  ImgDims inputDims; inputDims.channel = matImgPreprocessed.channels();inputDims.width = matImgPreprocessed.cols;inputDims.height = matImgPreprocessed.rows;float *dataHWC = new float[inputDims.channel * inputDims.width * inputDims.height]// Copy the image data to be detected to the dataHWC array.// The dataHWC[image_size] array here is the intermediate variable of the input MindSpore model tensor.float *ptrTmp = reinterpret_cast<float *>(matImgPreprocessed.data);for(int i = 0; i < inputDims.channel * inputDims.width * inputDims.height; i++){   dataHWC[i] = ptrTmp[i];}// Assign dataHWC[image_size] to the input tensor variable.auto msInputs = mSession->GetInputs();auto inTensor = msInputs.front();memcpy(inTensor->MutableData(), dataHWC,    inputDims.channel * inputDims.width * inputDims.height * sizeof(float));delete[] (dataHWC);对输入数据进行处理。bool PreProcessImageData(const LiteMat &lite_mat_bgr, LiteMat *lite_norm_mat_ptr) {  bool ret = false;  LiteMat lite_mat_resize;  LiteMat &lite_norm_mat_cut = *lite_norm_mat_ptr;  ret = ResizeBilinear(lite_mat_bgr, lite_mat_resize, 256, 256);  if (!ret) {    MS_PRINT("ResizeBilinear error");    return false;  }  LiteMat lite_mat_convert_float;  ret = ConvertTo(lite_mat_resize, lite_mat_convert_float, 1.0 / 255.0);  if (!ret) {    MS_PRINT("ConvertTo error");    return false;  }  LiteMat lite_mat_cut;  ret = Crop(lite_mat_convert_float, lite_mat_cut, 16, 16, 224, 224);  if (!ret) {    MS_PRINT("Crop error");    return false;  }  float means[3] = {0.485, 0.456, 0.406};  float vars[3] = {1.0 / 0.229, 1.0 / 0.224, 1.0 / 0.225};  SubStractMeanNormalize(lite_mat_cut, lite_norm_mat_cut, means, vars);  return true;}对输入Tensor按照模型进行推理,获取输出Tensor,并进行后处理。图执行,端测推理。// After the model and image tensor data is loaded, run inference.auto status = mSession->RunGraph();获取输出数据。auto names = mSession->GetOutputTensorNames();std::unordered_map<std::string, mindspore::tensor::MSTensor *> msOutputs;for (const auto &name : names) {    auto temp_dat =mSession->GetOutputByTensorName(name);    msOutputs.insert(std::pair<std::string, mindspore::tensor::MSTensor *> {name, temp_dat});  }std::string retStr = ProcessRunnetResult(msOutputs, ret);输出数据的后续处理。std::string ProcessRunnetResult(std::unordered_map<std::string,        mindspore::tensor::MSTensor *> msOutputs, int runnetRet) {  std::unordered_map<std::string, mindspore::tensor::MSTensor *>::iterator iter;  iter = msOutputs.begin();  // The mobilenetv2.ms model output just one branch.  auto outputTensor = iter->second;  int tensorNum = outputTensor->ElementsNum();  // Get a pointer to the first score.  float *temp_scores = static_cast<float *>(outputTensor->MutableData());  float scores[RET_CATEGORY_SUM];  for (int i = 0; i < RET_CATEGORY_SUM; ++i) {     if (temp_scores[i] > 0.5) {      MS_PRINT("MindSpore scores[%d] : [%f]", i, temp_scores[i]);     }    scores[i] = temp_scores[i];  }  // Score for each category.  // Converted to text information that needs to be displayed in the APP.  std::string categoryScore = "";  for (int i = 0; i < RET_CATEGORY_SUM; ++i) {    categoryScore += labels_name_map[i];    categoryScore += ":";    std::string score_str = std::to_string(scores[i]);    categoryScore += score_str;    categoryScore += ";";  }  return categoryScore;}原文:https://gitee.com/mindspore/docs/blob/r1.0/tutorials/lite/source_zh_cn/quick_start/quick_start.md
总条数:181 到第
上滑加载中