ios底部栏设计规范_iOS平台的移动UI设计规范

一、状态栏和导航栏

1、状态栏(Status Bars)就是iPhone*上方用来显示时间、运营商信息、电池电量的那个很窄的区域。

2、导航栏(Navigation Bars)就是状态栏之下的区域,一般来说导航栏中间是页面标题,左右是放置功能图标的区域。

在iPhone6/7/8设计中,状态栏的高度为20pt(40px),导航栏的高度是44pt(88px)。这两个区域在iOS7代之后就进行了一体化设计。所以它们加起来的高度是64pt(128px)。

二、大标题导航栏

1、大标题

在*新的苹果设计中导航出现了一种新形式:大标题。出现这种形式就是为了减少视觉噪音,让内容更加突出。

很明显大标题的设计很像报纸的版式设计,在*眼我们就会明白页面的主题。

大标题导航栏的高度一般为116pt(232px):这包括了20pt(40px)状态栏的高度,同时也能放得下34pt(68px)的大标题和辅助信息(如返回等图标)。

但是注意一下,大标题并不应该像传统导航一样常驻在页面之上,因为它太占空间了。所以在滑动页面时大标题会变成正常导航栏的64pt(128px)的高度。

2、标签栏(Tab Bars)

Tab就是点击的意思,Tab栏(也叫标签栏)指的是APP底部的区域,如微信底部常驻有聊天、通讯录、发现、我的四个图标。

iOS规范中Tab栏一般有五个、四个、三个图标的形式。也就是把宽度平分为五、四、三份。

iPhone6/7/8设计中,标签栏的高度为49pt(98px)。Tab栏的操作是*常用的,因为手指*方便点击而且这个栏是常驻在页面之上的。

所以Tab栏的图标至关重要。

因为很多用户可能因为看不懂图标而找不到重要功能的入口,通常我们会在Tab栏图标之下加上10pt(20px)的注释文字,这个注释文字一般来说都是非常浅的浅灰色。

3、标签栏图标

我们在标签栏上的图标一般来说30pt(60px)大小左右,苹果给出了四种不同形状标签栏图标的尺寸参考供大家设计时考虑。

其意义是让不同外形的图标看上去是差不多大的,保证图标的平衡。

标签栏图标的选中态应该是一个彩色,来区别于非选中状态。

三、工具栏(ToolBars)

我们在苹果自带浏览器底部就能看到工具栏。

工具栏提供了和当前任务相关的操作和按钮,在滑动时可以收起。

工具栏同Tab栏一样都是位于底部,但是高度略窄,它的高度是44pt(88px)。

四、闪屏资源

由于闪屏是一张完整的静态满屏图片,而不是诸如其他页面一样是由切图和文本拼成的,所以闪屏的适配更简单粗暴:我们需要提供不同尺寸的闪屏效果。

闪屏资源就是满尺寸的一张PNG,上端不需要状态栏里的信息,程序会在开发完毕时自动在闪屏中补上状态栏里的信息。

五、安全距离

作为iPhone全面屏系列手机,齐刘海无疑是一个特征。

但是全面屏给我们带来了使用上的问题:上下左右是圆角、顶部齐刘海使屏幕凹下一块。

所以在带有圆角和齐刘海的红色标注区域不应该放置任何功能,仅可在上端放置状态栏,底部圆角区域留白。

我们界面竖屏使用时左右临近手机边缘的区域不建议放任何操作,应留出一定的边距(Margin)。

这个边距是多少呢?没有明确严格的规定,但是一般的APP会留出16pt-24pt不等的边距防止用户在屏幕边缘不好点击。

不过内容展现却可以呈现在边距里。如果我们横屏使用手机时,左右同样不好点对吧?横屏同时还有令人闹心的“齐刘海”,所以同样左右需留出一定的边距来。

所以我们就得到一个安全距离的矩形,内容可以完整地呈现在这个安全距离内。

六、色彩

其实在iPhone上显示的色域要比我们作图时的RGB色域要广。

所以在iPhone上设计怎样的颜色都可以。只要符合产品气质并且在色彩心理学理论上思考,用什么颜色是设计师的自由。

官方建议的系统色彩如下:

iOS13 也引入了六种不透明的灰色,在少数透明色不好使的情况下可以使用它们。

七、字体

iOS中,英文使用的是San Francisco (SF)字体或者NewYork字体;中文使用的是苹方黑体。

安装好以后你会发现中文苹方的字族有那么我们设计界面时需要根据信息的逻辑权重分配粗细:不少可供选择的粗细,标题应该较粗,而说明字体应该较细并且可以设计成灰色。

其实字体的设计*重要的考量就是信息层级。

苹果提供的字号规范,其实并不适用中文,因为相同字号下,中文看起来比西文更大、更高,包括西文行高1.3~1.5倍,中文采用1.5~2倍。

包括内文,官方规范为17pt(34px),但是放到界面当中看会太大,看得不舒服,所以都可以适当调整。

比如内文用14pt(28px),或者精致的追求逼格大量留白、少量文本内容的的APP,可以采用12pt(24pt)。

八、启动图标

在设计模板还没有如今这么发达时,设计师需要设计启动图标(1024x1024px)之后按照程序员的要求切出几十个不同尺寸的图标。

比如,在手机中@3x情况下桌面图标尺寸为180x180px,在@2x情况下为120x120px;在应用商店图标需要使用的尺寸是1024x1024px;这个工作太烦人了,现在我们只需要专注在启动图标设计本身上了。

在苹果提供的这套资源中,有Template-AppIcons-iOS这个文件。

打开这个文件,用我们自己设计的启动图标替换掉智能对象里的内容,你会发现所有尺寸的图标都变成了我们的图标。然后我们把背景隐藏,切出这些图标即可。

图标设计建议使用AI等矢量软件,然后使用规范切出图像资源。

九、控件

控件包括:输入框、按钮、滑杆、页卡、开关等,在设计模板中已经全部列出。

为了让设计更符合整体产品品牌调性,这些控件都可以做成自定义的设计样式,但是这样会增加工作量和切图资源。

所以一般我们在诸如设置界面这些无需太体现设计感的页面中都使用系统默认控件,而在一些品牌感需要强调的页面或产品则会使用自定义的样式。

如果我们想自己设计控件,那么注意两件事:

*,点击区域基本符合44pt(88px)原则,也就是在手机上大小大概是7mm-9mm,适合手指点击;第二,要设计操作的不同状态,不要只设计一种状态。

十、键盘

在设计模板中您也可以找到键盘的设计。

这里需要提醒的是,很多朋友做界面设计时不考虑输入时键盘会遮挡到的空间。

如果考虑到键盘弹起遮挡住的内容,那么我们的一些界面中的输入框和信息可能都需要上移了。

当然也不是说可能被键盘遮挡的地方不可以防止任何内容,也有一种方式就是当输入一个表单时,页面会垂直定位到当前输入的位置。

【Android】删除某目录\整个文件夹的文件

删除某目录下文件:

%title插图%num
private void deleteAllFiles(File root) {
File files[] = root.listFiles();
if (files != null)
for (File f : files) {
if (f.isDirectory()) { // 判断是否为文件夹
deleteAllFiles(f);
try {
f.delete();
} catch (Exception e) {
}
} else {
if (f.exists()) { // 判断是否存在
deleteAllFiles(f);
try {
f.delete();
} catch (Exception e) {
}
}
}
}
}
只要把传入参数设置成要删除的目录即可。

删除整个文件夹里面的文件:

 

%title插图%num
使用时记得添加操作文件的权限!

<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />

<uses-permission android:name=”android.permission.MOUNT_UNMOUNT_FILESYSTEMS” />

<uses-permission android:name=”android.permission.WRITE_MEDIA_STORAGE” />
//flie:要删除的文件夹的所在位置
private void deleteFile(File file) {
if (file.isDirectory()) {
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++) {
File f = files[i];
deleteFile(f);
}
file.delete();//如要保留文件夹,只删除文件,请注释这行
} else if (file.exists()) {
file.delete();
}
}

评论:
suquan629
岭南散人:代码有 bug,如果传入的是一个文件的话,那个文件不会被删除。因为没有处理单个文件的逻辑。 new File(“e:/IDA/1.txt”) 你可以传这个参数试试,当然之前你先构造好这个文件。
zhuang_1008
zhuang_1008:if (f.isDirectory()) { // 判断是否为文件夹 deleteAllFiles(f); try { f.delete(); } catch (Exception e) { } } else { if (f.exists()) { // 判断是否退出(未被使用) deleteAllFiles(f); try { f.delete(); } catch (Exception e) { } } } 如果不是目录 都可以直接删除文件了 为什么还要迭代?死循环?
Etzmico
伊茨米可回复:没错呀。 if文件夹,else文件。要不哪来的被使用…… 亲,自己试试就知道啦,要实践,不能光靠看和想~
zhuang_1008
zhuang_1008回复伊茨米可:*对死循环
zhuang_1008
zhuang_1008回复伊茨米可:哪来的文件夹,if里是文件夹,else里面就是文件了
Etzmico
伊茨米可回复:文件夹中文件夹
zhuang_1008
zhuang_1008:if (f.exists()) { // 判断是否退出(未被使用) 注释亮了
Etzmico
伊茨米可回复:算了,自己去试试吧,理论家伤不起……实践出真知。
Etzmico
伊茨米可回复:只知其一不知其二……莫非你在windows系统中删文件时没遇到“该文件正在被使用”的提示么……汗。。
zhuang_1008
zhuang_1008回复伊茨米可:你知道exists这个方法的意思是什么吗?是占用吗?这个方法是判断文件或者文件夹是否存在的.
Etzmico
伊茨米可回复:你不会以为我当成exit了吧?退出是针对文件,括号里解释了。
mingmingsuper
皓月明:很好用已经测试了,不过这种在Android 10上只适合删除private的文件
qq_44060543
LccccccI:好使,记得添加权限
qq_33346542
qq_33346542:不好使,删不掉
ZhangXuxiaoqingnian
勤奋的小狼回复:只要权限全,就没问题的

深度评测阿里云、腾讯云和华为云

从全球的维度来说,公有云市场正在面临大爆发,随之而来的是各大云服务运营商之间激烈的市场竞争态势,新老云服务公司们不断暗自发力,抢占国内乃至全球公有云服务市场的“高地”。

近日,国际数据公司IDC发布了《全球公有云服务市场(2018下半年)跟踪》报告,根据报告显示,在整个2018年,全球公有云IaaS市场规模已经达到359.7亿美元的规模,相比去年同期大幅增长了45%,显然,全球范围的云服务市场都在持续迎来大爆发。

在“头部”公有云IaaS服务商中,IDC公布了全球前10大品牌,其中有包括阿里巴巴、腾讯、中国电信、金山云这4家在内的中国企业上榜,几乎占据了前十榜单中的一半。对比五年前国内仅有阿里一家入围前十,这个成绩表明了中国云服务市场在近些年发展的速度非常快。

从2016年开始,中国市场就已经成为仅次于美国的全球第2大公有云IaaS市场。仅就国内市场来说,2018年中国公有云IaaS市场比去年同期增长了86.1%,相对于全球市场45%的平均增速,中国云服务市场的发展速度可谓“一骑*尘”。

需要指出的是,国内特殊的IT结构导致现阶段私有云市场在规模上大于公有云市场,但从海外市场的情况来看,公有云市场的增速和渗透率都超过私有云,这给了国内公有云服务市场更大的想象空间。

同时,相比于国外市场,国内互联网行业的快速发展也在推动公有云服务市场的飞速增长,可以肯定的是,在未来很长一段时间内,中国公有云IaaS市场增速仍然会继续高于全球平均水平,中国企业在全球公有云市场中的地位和份额也将继续增加。

近些年来,国内的阿里巴巴、腾讯、中国电信这三家企业和国外亚马逊旗下的AWS一直稳居中国公有云市场头部梯队。在第二梯队中,金山云和百度智能云发展*为迅猛,金山云在2018年直接冲到全球前十的位置,百度智能云也在规模上成为国内市场排名第5的公有云服务品牌,营收同比增速更是超过300%。

在中国互联网、科技行业中,阿里巴巴、腾讯,在加上近些年愈发重视云服务领域的华为,这四家一直是国内云服务市场会拿来直接类比的厂商,但这四家显然是“有人欢喜有人忧”,它们在各自领域的技术特色和发展侧重也不尽相同,取得的成绩也“各有得失”。

阿里云,毫无争议的中国云服务*品牌

作为中国唯一一家世界排名前5的顶级云服务提供商,阿里云不仅在国内稳坐市场老大的位置,更是在2018年实现了92.6%的大幅增长。

作为国内*早押宝云服务市场的头部厂商,阿里云早已成为毫无争议的中国云服务*品牌。在去年3月长城战略咨询与科技部火炬中心联合发布的“2017中国独角兽企业榜单”中,阿里云以390亿美元的估值在所有上榜企业中排名第5,相对于那时估值只有33亿美元的腾讯云和估值为21.2亿美元的金山云,阿里云的优势非常明显。

创立于2009年的阿里云发展至今已有十个年头,作为阿里巴巴集团旗下的云计算品牌,阿里云主要以在线公共服务的方式,为企业、开发者和政府机构等提供计算和数据处理服务。

官方信息显示,阿里云目前的服务范围已经覆盖两百多个国家和地区,在全球18个地域开放了49个可用区,在全球部署了两百多个飞天数据中心。

阿里云创立的第二年,国家就相继出台了多项政策以支持国内云服务行业发展,在良好的政策保障优势、技术与数据优势、先发优势下,阿里云得到了飞速发展。

从产品和服务上来看,阿里云服务目前主要覆盖IaaS(基础设施即服务)、PaaS(平台即服务)、SaaS(软件即服务)三大云服务类型,产品涉及云计算基础、安全、大数据、人工智能、企业应用、物联网等众多领域。

基础云计算服务器层面,阿里云​​​​目前从云服务器ECS已经衍生出了多个云服务器系列,包括适用于初级用户的轻量应用服务器、适合高性能场景的多种云服务器等。

安全产品及服务层面,阿里云在2014年就曾帮助一家游戏公司抵御了“全球互联网史上*大”的一次DDoS攻击,这让阿里云安全服务“名声在外”。

包括大数据计算、数据可视化、大数据搜索与分析、数据开发、大数据应用等在内的大数据系列产品,包括智能语音交互、图像搜索、自然语言处理、印刷文字识别、人脸识别、机器翻译、图像识别、视觉计算、内容安全、机器学习平台、城市大脑开放平台等在内的人工智能(AI)系列产品,阿里云均有不同程度的“建树”。

另外,企业应用、物联网应用、开发与运维工具服务……阿里云也都有所深耕。

目前来看,阿里云在全球云计算领域已经构建起强大的技术及市场优势。

人工智能领域,阿里云旗下*新的人工智能系统ET大脑已具备智能语音交互、图像/视频识别、机器学习、情感分析等技能。基于ET大脑,阿里云还衍生出了ET城市大脑、ET工业大脑、ET医疗大脑、ET环境大脑等。

另外,阿里云旗下还有自主研发的超大规模通用计算操作系统——飞天系统,目前该系统已经全面地服务于全球范围内的客户。据官方介绍,飞天系统能够将遍布全球的百万级服务器连成一台超级计算机,以在线公共服务的方式提供计算能力。

市场层面,阿里云在近年国内市场也一直保持着*优势,据弗若斯特沙利文研究报告显示,2018年上半年,阿里云在国内的市场份额为17.0%,远高于第二名腾讯云的9.1%。

以阿里云目前的增速来看,未来随着互联网技术、5G技术的深入发展,它以后的市场发展潜力仍然十分巨大。在已经构筑起强大的品牌、规模、技术等多方面优势的背景下,阿里云目前几乎没有明显短板,再加上阿里巴巴达摩院的加持,阿里云大概率还是要成为国内其他云服务产商无法跨越的“大山”。

腾讯云,B端、G端全面发力

作为国内云服务市场行业老二,腾讯云眼见阿里云的“一路狂奔”,自然也不甘心“屈居人下”,所以近些年来凭借着腾讯社交帝国的战略资源和产业互联网的发展方向,腾讯云也在奋力狂奔。

就在上个月,腾讯云、腾讯产业投资基金、东华软件和华体科技四方还高调地联合宣布了以8.7亿元的价格中标成都市“智慧绿道”项目。这背后,是腾讯云在B端及政务项目领域的不断发力。

根据腾讯云官方微信发布的推送显示,仅在今年六月上旬,包括成都市“智慧绿岛”项目在内,腾讯云在八天时间里就火速拿下了七个大项目,客户包含中国政务服务平台,海通证券、成都智慧绿道、中华保险,辽宁省,Vipkid,贝店、华米等。

在政务服务平台项目上,腾讯云目前已经服务了中国政务服务平台、成都智慧绿道、辽宁省人民政府、沈阳市人民政府、沈抚新区、数字广东、数智贵阳等。

B端服务领域,腾讯云与中华保险将在云计算架构、大数据、保险科技等多层次开展合作;教育行业,腾讯云与在线教育机构Vipkid展开合作,另外腾讯云的客户还有社交电商平台贝店、“小米生态链*股”华米科技、多达六千多家的金融企业等。

相比于竞争对手,腾讯云的优势领地目前还是聚焦在社交电商、游戏、物流和出行等腾讯“生态”优势领域。万达、蘑菇街、小红书等电商品牌都采用的是腾讯云的解决方案;腾讯云还服务了国内几乎所有游戏业排名前200的游戏厂商;物流领域,腾讯云的客户主要包括顺丰、中外运、货车帮等。

近年来,腾讯云也在积*对标阿里云的AI+大数据+云计算并举的策略,并在为数众多的国内中小银行和金融机构里获得了大量案例落地。

随着腾讯产业互联网战略的发布,腾讯云更是加快了自身发展的步伐。根据官方介绍,“腾讯云已经成为中国*家服务器总量超百万的企业,腾讯带宽峰值突破100T,腾讯在服务器、带宽能力上,率先进入了‘双百’时代”。

不过,腾讯云目前在国内云服务市场的整体优劣势也很明显。那就是产品体验还不错,但技术、规模等相对于阿里云还落后很多。除了创立至今一直面临的“照搬友商”的质疑之外,腾讯云目前在人工智能、企业级互联网架构等技术领域和产品细节打磨、服务等层面均与阿里云有着不小的差距。

华为云,“边缘化”是现状,但未来仍有机会

相比于阿里云腾讯云、百度智能云这三家,同样在大众互联网、科技领域声量巨大的华为云近些年来的发展有些“滞后”。

两年前,在华为2017全联接大会上,华为轮值CEO、副董事长郭平对外表示,“华为将脚踏实地,决心和伙伴一起打造世界上五朵云之一”。

但现实很残酷,时间来到现在,华为云在国内云服务市场中的份额占比几乎已经失去了存在感,“边缘化”严重。Canalys发布的2019年*季度云计算领域行业报告显示,阿里云的市场份额是47.3%,腾讯云为15.4%,亚马逊AWS为8.8%,但华为云的市场份额都没有被单列出来,直接被计入了“其他”中。

根据IDC发布的数据显示,华为云目前在国内云服务市场中排名第10,市场份额只有0.9%。显然,近几年华为云的发展状况十分堪忧,与头部品牌的差距正变得越来越“遥不可及”,成为所谓的“世界上5朵云之一”的愿景已经很难实现。没有市场,就更别谈技术实力、案例与数据积累了。

不过,在中国政企市场中具有强大影响力的华为云却还有它未来进一步发展的机会。国内党政市场云计算市场规模潜力巨大,而且对技术的要求又没有那么高,所以政企需求一直是国内巨头们收割行业地位的“跳板”。以华为在中美贸易战后“一战封神”的行业地位,它未来还是有可能会获得大量的政企服务订单,这有可能会助力华为云的进一步发展。

当然,即便是在政企优势领域,华为云仍要面对影响力巨大的阿里巴巴、腾讯的竞争,未来华为云想要突围而出,变数还是非常大。

从行业的发展来看,华为云在这些年的时间里走了大量“弯路”,技术积累与产品功能远没有阿里云等竞品丰富,这就直接导致了华为云在落地和应用规模上的受限。

具备多年先发技术优势、市场优势的阿里云等竞争对手将会成为华为云想要进一步发展之路上*大的拦路虎。

Android EditText输入框自动提示

所示的图片中输入as前两个字母,后面就会提示相应的结果提示,这在apidemo中也有类似例子的提供,网上传的也基本都是那个例子。
这个功能用处不大,但是在于新意不错,说专业一点就是用户体验不错。
每个事情都有缺点,这个的坏处就是必须输入两个以上的字符,两个!
实现此功能的是EditText的子类控件AutoCompleteTextView。既是子类,所以有着全部父类的属性,即用法与EditText相同。(MultiAutoCompleteTextView这个的属性更加强大,有兴趣的朋友可以继续研究)。

来看看功能实现代码

 

public class Enter extends Activity {

String[] result_about_a = {“andexplorer”,”astro”};
private AutoCompleteTextView field_text; // 定义AutoCompleteTextView对象

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

field_text = (AutoCompleteTextView) findViewById(R.id.et1);
//自动提示
ArrayAdapter<String> adapt = new ArrayAdapter<String>(this,
android.R.layout.simple_dropdown_item_1line,
result_about_a);
field_text.setAdapter(adapt);

}
}

xml布局部分

<AutoCompleteTextView
android:id=”@+id/et1″
android:hint=”软件,游戏,尽在96商城” // 此处为自己定义的属性,可不要。提示信息
android:layout_width=”220px”
android:layout_height=”50px”
android:layout_marginLeft=”30px”
>

但是,此方法的一个*大不好处就是上面的数组自定义。这个简直就是愚蠢的做法,应该可以在创建一个数据库用来存放一些被搜索的内容,然后等用到的时候再用Adapter来相应的对应上,但是自己还没那样做。还是惰性太大啊。希望有此经验的朋友有机会可以给我一些建议。

将Activity打成jar包供第三方调用

将Activity打成jar包供第三方调用(解决资源文件不能打包的问题)

*近有一个需要,我们公司做了一个apk客户端,然后其他的公司可以根据自己的需要来替换里面的资源图片,文字等一些资源文件问题,我本来想这个简单,用两个工程直接替换里面的资源文件就行,老大说,这样子不好,如果要改需要改两个客户端,而且还麻烦,叫我将所有的Activity打成Jar包的形式,这样子我们改了里面的内容就直接发布Jar包出去,其他公司直接下载Jar来使用,这样子他们自己公司也能更好的维护。

所以我就想直接将Activity打成Jar包,可是在使用的过程中发现这样子根本行不通,因为如果Activity引用了布局文件的话,比如R.layout.XXX或者R.string.XXX,我们使用的时候会报资源ID未找到的异常,在官网上看到可以将另一个工程当做Libraryhttp://developer.android.com/tools/projects/projects-eclipse.html,可是这样子需要将源码给到人家,不能直接发布Jar包,貌似不是我要的那种情况,今天我教大家如果将Activity打成Jar包的形式

1.我们新建一个Android工程,取名为ActivityLibrary,这个就是等下我们需要打包成Jar的工程

%title插图%num

注:MResource这个类很重要,主要是它的作用,利用反射根据资源名字获取资源ID(其实系统也自带了根据资源名字获取资源ID的方法getResources().getIdentifier(“main_activity”, “layout”, getPackageName());*个参数是资源的名字,第二个参数是资源的类型,例如layout, string等,第三个是包名字)

[java]  view plain copy

  1. package com.example.activitylibrary;
  2. import android.content.Context;
  3. /**
  4.  * 根据资源的名字获取其ID值
  5.  * @author mining
  6.  *
  7.  */
  8. public class MResource {
  9.     public static int getIdByName(Context context, String className, String name) {
  10.         String packageName = context.getPackageName();
  11.         Class r = null;
  12.         int id = 0;
  13.         try {
  14.             r = Class.forName(packageName + “.R”);
  15.             Class[] classes = r.getClasses();
  16.             Class desireClass = null;
  17.             for (int i = 0; i < classes.length; ++i) {
  18.                 if (classes[i].getName().split(“\\$”)[1].equals(className)) {
  19.                     desireClass = classes[i];
  20.                     break;
  21.                 }
  22.             }
  23.             if (desireClass != null)
  24.                 id = desireClass.getField(name).getInt(desireClass);
  25.         } catch (ClassNotFoundException e) {
  26.             e.printStackTrace();
  27.         } catch (IllegalArgumentException e) {
  28.             e.printStackTrace();
  29.         } catch (SecurityException e) {
  30.             e.printStackTrace();
  31.         } catch (IllegalAccessException e) {
  32.             e.printStackTrace();
  33.         } catch (NoSuchFieldException e) {
  34.             e.printStackTrace();
  35.         }
  36.         return id;
  37.     }
  38. }

当我们的资源Id是一个数组的时候,我们要用下面的方法

[java]  view plain copy

  1. public static int[] getIdsByName(Context context, String className, String name) {
  2.     String packageName = context.getPackageName();
  3.     Class r = null;
  4.     int[] ids = null;
  5.     try {
  6.       r = Class.forName(packageName + “.R”);
  7.       Class[] classes = r.getClasses();
  8.       Class desireClass = null;
  9.       for (int i = 0; i < classes.length; ++i) {
  10.         if (classes[i].getName().split(“\\$”)[1].equals(className)) {
  11.           desireClass = classes[i];
  12.           break;
  13.         }
  14.       }
  15.       if ((desireClass != null) && (desireClass.getField(name).get(desireClass) != null) && (desireClass.getField(name).get(desireClass).getClass().isArray()))
  16.         ids = (int[])desireClass.getField(name).get(desireClass);
  17.     }
  18.     catch (ClassNotFoundException e) {
  19.       e.printStackTrace();
  20.     } catch (IllegalArgumentException e) {
  21.       e.printStackTrace();
  22.     } catch (SecurityException e) {
  23.       e.printStackTrace();
  24.     } catch (IllegalAccessException e) {
  25.       e.printStackTrace();
  26.     } catch (NoSuchFieldException e) {
  27.       e.printStackTrace();
  28.     }
  29.     return ids;
  30.   }

 

LibraryActivity这里面比较简单,一个Button,一个TextView,一个ImageView

[java]  view plain copy

  1. package com.example.activitylibrary;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import android.view.View.OnClickListener;
  6. import android.widget.Button;
  7. import android.widget.TextView;
  8. import android.widget.Toast;
  9. public class LibraryActivity extends Activity {
  10.     String msg = “我是来自Jar中的Activity”;
  11.     @Override
  12.     protected void onCreate(Bundle savedInstanceState) {
  13.         super.onCreate(savedInstanceState);
  14.         setContentView(MResource.getIdByName(getApplication(), “layout”“activity_main”));
  15.         TextView mTextView = (TextView) findViewById(MResource.getIdByName(getApplication(), “id”“textView1”));
  16.         mTextView.setText(msg);
  17.         Button mButton = (Button) findViewById(MResource.getIdByName(getApplication(), “id”“button1”));
  18.         mButton.setText(msg);
  19.         mButton.setOnClickListener(new OnClickListener() {
  20.             @Override
  21.             public void onClick(View v) {
  22.                 Toast.makeText(getApplication(), msg, Toast.LENGTH_SHORT).show();
  23.             }
  24.         });
  25.     }
  26. }

Activity的布局

[html]  view plain copy

  1. <RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”
  2.     xmlns:tools=“http://schemas.android.com/tools”
  3.     android:layout_width=“match_parent”
  4.     android:layout_height=“match_parent”
  5.     tools:context=“.MainActivity” >
  6.     <Button
  7.         android:id=“@+id/button1”
  8.         android:layout_width=“wrap_content”
  9.         android:layout_height=“wrap_content”
  10.         android:layout_alignParentLeft=“true”
  11.         android:layout_alignParentRight=“true”
  12.         android:layout_alignParentTop=“true” />
  13.     <TextView
  14.         android:id=“@+id/textView1”
  15.         android:layout_width=“wrap_content”
  16.         android:layout_height=“wrap_content”
  17.         android:layout_alignParentLeft=“true”
  18.         android:layout_alignParentRight=“true”
  19.         android:layout_below=“@+id/button1” />
  20.     <ImageView
  21.         android:id=“@+id/imageView1”
  22.         android:layout_width=“wrap_content”
  23.         android:layout_height=“wrap_content”
  24.         android:layout_alignParentBottom=“true”
  25.         android:layout_alignParentLeft=“true”
  26.         android:layout_alignParentRight=“true”
  27.         android:layout_below=“@+id/textView1”
  28.         android:layout_marginTop=“28dp”
  29.         android:src=“@drawable/ic_launcher” />
  30. </RelativeLayout>

2.我们将ActivityLibrary工程打成Jar包。右键工程—>Export—->Java—>JAR file—->Next如下图

%title插图%num%title插图%num

只勾选src目录,其他的都不勾选,如图

%title插图%num

通过上面这几步我们就将Android工程打包好了

3.我们来使用刚刚打包好的Activity,我们还需要刚刚那个工程的资源文件,因为我们刚刚只打包了src,资源文件不能打包,因此我们需要自己拿出来,我们需要吧Library.jar加入到libs里面去,然后用到的资源文件,如果layout,string之类的拷贝到对应工程的地方去

%title插图%num

这个工程一个MainActivity,里面一个按钮,点击按钮跳转到Library中的Activity中,比较简单我直接把代码贴上

[java]  view plain copy

  1. package com.example.androidlibraryinvoke;
  2. import android.app.Activity;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. import android.view.View;
  6. import android.view.View.OnClickListener;
  7. import android.widget.Button;
  8. public class MainActivity extends Activity {
  9.     @Override
  10.     protected void onCreate(Bundle savedInstanceState) {
  11.         super.onCreate(savedInstanceState);
  12.         setContentView(R.layout.main);
  13.         Button mButton = (Button) findViewById(R.id.button1);
  14.         mButton.setOnClickListener(new OnClickListener() {
  15.             @Override
  16.             public void onClick(View v) {
  17.                 Intent intent = new Intent();
  18.                 intent.setClassName(getApplication(), “com.example.activitylibrary.LibraryActivity”);
  19.                 startActivity(intent);
  20.             }
  21.         });
  22.     }
  23. }

我们需要在AndroidManifest.xml注册LibraryActivity,否则报Activity找不到异常,总体来说就是这样子,这样子我们将Activity打成的Jar包和资源文件一起发出去,人家就可以调用可,如果你觉得我写的对你有帮助的话你就顶一下,谢谢!

Tomcat服务器如何重启

非安装版的:
找到tomcat正确路径,然后:
运行 bin/shutdown 关闭Tomcat服务
再运行 bin/startup 启动Tomcat服务

安装版的:
可以在服务里面找到Apache Tomcat,将启动类型改为你需要的类型。

其他:
在Windows下将tomcat生成服务,每次Windows就可自动重启Tomcat
可以弄成windows服务
1 cmd 进入 tomcat bin目录
2 执行 service install
完成
必须确保环境变量已配置正确

XP的步骤:
开始菜单–运行–services.msc–Apache Tomcat服务

 

 

命令行启动方法:
假设tomcat的路径:C:\tomcat
如果你的toamcat已经启动:在命令行中进入tomcat安装目录
C:\tomcat\bin>stutdown
之后 C:\tomcatbin>startup
这样tomcat完成了一次重启。

重启后,*次运行会比较慢,第二次运行就快了,*次的时候tomcat在做编译工作,第二次运行时已经编译好了

Centos7搭建FTP服务详细过程

一、安装VSFTP
1.为了方便后续操作,现将用户切换到root用户    su –

2.查看是否已经安装vsftpd

方法一:

[root@localhost ~]# rpm -q vsftpd

vsftpd-3.0.2-22.el7.x86_64

方法二:

[root@localhost ~]# vsftpd -v

yum安装vsftpd

[root@localhost ~]# yum -y install vsftpd
%title插图%num

3.安装完成后,查看位置

[root@localhost ~]# whereis vsftpd

vsftpd: /usr/sbin/vsftpd /etc/vsftpd /usr/share/man/man8/vsftpd.8.gz

4.直接启动VSFTP服务

[root@localhost ~]# systemctl start vsftpd.service

[root@localhost ~]#

5.查看是否启动成功

[root@localhost ~]# netstat -npal|grep vsftpd

tcp6    0   0 :::21     :::*     LISTEN      4432/vsftpd

可以看到服务已经启动,端口为21,pid为4432

 

6.关闭SELinux限制,添加防火墙白名单

①设置关闭SELinux对ftp的限制

[root@localhost ~]# getsebool -a | grep ftp

ftp_home_dir –> on

ftpd_anon_write –> off

ftpd_connect_all_unreserved –> off

ftpd_connect_db –> off

ftpd_full_access –> on

ftpd_use_cifs –> off

ftpd_use_fusefs –> off

ftpd_use_nfs –> off

ftpd_use_passive_mode –> off

httpd_can_connect_ftp –> off

httpd_enable_ftp_server –> off

sftpd_anon_write –> off

sftpd_enable_homedirs –> off

sftpd_full_access –> off

sftpd_write_ssh_home –> off

tftp_anon_write –> off

tftp_home_dir –> off

 

[root@localhost ~]# setsebool -P ftpd_full_access on

 

②将ftp加入防火墙白名单

firewall-cmd –permanent –zone=public –add-service=ftp

firewall-cmd –reload

查看防火墙状态:firewall-cmd –list-all

二、配置修改
1.修改配置文件

[root@localhost ~]# cd /etc/vsftpd/

[root@localhost vsftpd]# vim vsftpd.conf

 

不允许匿名访问(不登录默认访问某目录/var/ftp)

anonymous_enable=NO

允许ascii文件上传和下载

ascii_upload_enable=YES

ascii_download_enable=YES

将用户限制在为其配置的主目录

chroot_local_user=YES

chroot_list_enable=YES

chroot_list_file=/etc/vsftpd/chroot_list

三、匿名登录
匿名登陆
如果设置anonymous_enable=NO表示可以匿名登陆,保存后重新启动vsftp服务systemctl restart vsftpd.service),即可以匿名登陆ftp服务(ftp ipaddr),密码是空,对应目录是/var/ftp,如果你在配置里面配置了anonymous_enable=NO,匿名就无法登录。

 

四、多用户配置
1.首先需要在vsftp.conf添加如下配置

#设置启用虚拟用户功能

guest_enable=YES

#制定宿主用户名(我们后续需要为我们的系统增加该用户)

guest_username=ftpuser

#制定虚拟用户配置文件放置文件夹(需要我们自己建立)

user_config_dir=/etc/vsftpd/vuser_conf

#允许写

allow_writeable_chroot=YES

 

2.创建宿主用户

#创建宿主主文件夹

cd /home

mkdir vsftpd

# 创建用户 ftpuser 指定 `/home/vsftpd` 目录

# -s /sbin/nologin ftpuser 表示不允许该用户通过命令行方式登录

useradd -g root -M -d /home/vsftpd -s /sbin/nologin ftpuser

# 设置用户 ftpuser 的密码

passwd ftpuser

# 把 /home/vsftpd 的所有权给ftpuser.root

chown -R ftpuser.root /home/vsftpd

 

3.创建虚拟用户信息文件

vsftp目录下

cd /etc/vsftpd/

创建用户信息文件

touch vuser_passwd

vim vuser_passwd

#编辑如下内容,创建虚拟账户信息,奇数行为用户名,偶数行为密码

ftp-user1

123456

ftp-user2

123456

 

4.生成虚拟用户数据文件

db_load -T -t hash -f /etc/vsftpd/vuser_passwd /etc/vsftpd/vuser_passwd.db

chmod 600 /etc/vsftpd/vuser_passwd.db

在当前文件夹下生成一个vuser_passwd.db文件

 

5.编辑pam认证文件

vim /etc/pam.d/vsftpd

将其他都注释掉,添加下面两行;

注:db=/etc/vsftpd/vuser_passwd 中的vuser_passwd 是你生成的虚拟用户的db文件,这里不要加扩展名。

系统为32位:

auth required pam_userdb.so db=/etc/vsftpd/vuser_passwd account

required pam_userdb.so db=/etc/vsftpd/vuser_passwd

 

系统为64位:

auth required /lib64/security/pam_userdb.so db=/etc/vsftpd/vuser_passwd

account required /lib64/security/pam_userdb.so db=/etc/vsftpd/vuser_passwd

 

查看系统位数

getconf LONG_BIT

 

6.为虚拟账户创建访问根目录,要在宿主用户下

# 下面是目录结构

/home/vsftpd

├──ftp-user1

│         └── files

└──ftp-user2

└──files

修改权限

chmod 777 ftp-user1

chmod 777 ftp-user2

 

7.创建虚拟用户配置目录

cd /etc/vsftpd/

#创建上述配置文件中配置的虚拟用户文件夹,一定要对应

mkdir vuser_conf

cd vuser_conf

#创建虚拟用户配置文件,文件名称要与虚拟用户名称相同

#这里我们配置两个虚拟用户就创建两个配置文件

touch ftp-user1 ftp-user2

#编辑两个文件,加入以下信息(注意加粗部分要替换为你虚拟账户要访问的根目录名称)

local_root=/home/vsftpd/ ftp-user1

write_enable=YES

anon_umask=022

anon_world_readable_only=NO

anon_upload_enable=YES

anon_mkdir_write_enable=YES

anon_other_write_enable=YES

 

8.创建chroot_list

cd /etc/vsftpd

#创建使当前配置的虚拟用户允许访问

[root@localhost vsftpd]# touch chroot_list

[root@localhost vsftpd]# vim chroot_list

#写入虚拟用户名

ftp-user1

ftp-user2

 

9.重启VSFTP服务

systemctl restart vsftpd.service

10.可以在windows中访问测试,或者使用FileZilla连接
%title插图%num

问题汇总:

1、解决报错 500 OOPS: vsftpd: refusing to run with writable root inside chroot()

添加配置

allow_writeable_chroot=YES # 如果启用了限定用户在其主目录下需要添加这个配置。

2、登录报错530,日志显示

pam_unix(vsftpd:auth): check pass; user unknown

检查一下/etc/pam.d/vsftpd文件配置,一般是pam认证文件配置错误。

腾讯云和阿里云对比哪个好?云计算优势测评

计算市场争夺阿里云作为名副其实的国内业界*,名声非常大,不过*近 IT 之家的事闹出来之后,我有点庆幸*终没有选择它。腾讯云算是业界老二,而且有着腾讯这个强大的靠山,云服务产品的种类和质量都不错。

上个月阿里云在云栖大会上宣布降价,昨天腾讯云方面也推出了全线降价活动,对包年包月产品均提供了大幅度的降价优惠。阿里和腾讯在云计算领域之争继续上演,双方都想通过价格优势带来用户的高增长,抢夺市场份额。

这对于云计算用户来说自然是一件好事,但是如果让价格完全左右企业或个人用户的购买决策的话,那么*终很可能会出现已购产品无法满足需求,从而不得不被迫迁移的情况。笔者的观点很简单,在考虑价格因素之前,应该先从产品性能、服务等多方面进行评估。

在选择自己的云服务器之前,我也在腾讯云和阿里云之间犹豫过,并对两家的产品做过一些简单的对比。下文中会简要分享一下对比结果。

在对比每一款产品时,本文先通过一系列的标准化测试比较产品的性能,然后再结合产品的*新优惠价格因素进行评价。至于两家的产品到底谁的性能更好、性价比更高,一切还是要用数据说话。

本文采用的测试工具和方法介绍,请查看配套文章:云计算产品性能测试指南。对象存储部分的脚本可在 Github 项目中查看。阅读期间,如果你觉得具体对比过程太长,可以直接跳到本文结语部分查看对比结论。

选择对比产品腾讯云和阿里云都是典型的 IaaS 服务商,产品种类繁多。限于时间和成本,没办法对所有产品进行一一对比,只能有选择性地比较一些基础产品和服务。
根据 AWS Web 应用参考架构,一个高可用、可伸缩的网站至少需要使用以下云计算资源:云服务器、云数据库、对象存储服务、负载均衡、内容分发等。因此我们在本文中主要对比云服务器、云数据库和对象存储这三个比较基础的产品。

%title插图%num

网站参考架构图:以 AWS 服务为例。

腾讯云*新服务器活动–云服务器免费送。

试用领取有人能领到180天。

腾讯云领取优惠券地址

阿里云领取优惠券地址

%title插图%num

 

对比产品的英文简称,下文在谈到对应产品时,将使用其简称表示。

云服务器对比云服务器是所有云计算服务商提供的*基础产品。厂商一般会根据分配的资源划分云服务器的级别和规格。但是由于采用的基础硬件、架构和调优技术存在差别,类似配置的云服务器之间也可能有较大的性能差异。

如果想了解并比较不同厂商云服务器的差异,*好的方式就是运行基准测试。

性能测试准备在开始测试之前,我们先在两家创建相同配置的两台云服务器,尽量确保测试结果之间具备可比性。付费方法均采用按量计费,使用包年包月服务器进行测试的成本较高。

腾讯云和阿里云针对按量计费的云服务器,均要求账户内有一定的余额:腾讯云好像没有*低充值要求,充值 10 元即可;阿里云要求账户内至少有 100 元余额。
测试云服务器的具体配置如下:

%title插图%num

这里指出一点,由于阿里云 ECS 云硬盘*小为 40G ,而腾讯云 CVM 默认 Linux 系统赠送 20G ,为了在后面对比二者价格时有可比性,将 CVM 的云硬盘调整为 40G 。
除了系统盘默认大小不同外,测试云服务器在 CPU 、内存、操作系统等方面均为同一规格的配置。这个规格的配置也是中小型网站部署的推荐配置,应该能够满足大部分用户的需求。
性能测试过程由于测试的流程比较长,在本文中只简要介绍下所使用的工具及对应关注的指标。具体的测试操作步骤,我会在云计算产品性能测试指南中介绍。
在测试云服务器之前,我参考了许多相关评测文章,*终决定使用如下工具和指标:

 

%title插图%num

有关其中所使用工具和指标的具体说明,请移步到这里:云计算产品性能测试指南。

性能测试结果GeekBench 会将测试结果上传到自己的网站,本文测试结果的访问地址如下:

%title插图%num

CVM

ECS

各项指标结果汇总如下:

从数据来看,腾讯云的 CVM 在 UnixBench 和 GeekBench 两个综合性测试工具下的得分都高于阿里云的 ECS 。

%title插图%num

 

CPU 延迟和内存性能方面, ECS 略胜一筹,但是优势不大。在磁盘 I/O 性能上,阿里云的表现接近在启动实例配置时所介绍的 500 IOPS 。但是与腾讯云相比逊色不少,CVM 的磁盘随机读 /写的 IOPS (每秒的输入输出量,或读写次数)均在 4000 左右。

%title插图%num

其实看到二者在磁盘 I/O 性能上差距居然这么大,笔者刚开始很诧异,还以为测试命令输入有误,不过反复测试确认之后,可以证实这个数据并没有错。同时也向客服方面了解,得到的回复是: CVM 的磁盘I/O *大性能指标的确可以达到 4000 ,但是并不承诺一直保持该性能。这点可以理解,随着租户的增加,*大性能指标很有可能会逐步下降。
*后要注意的是,虽然我们使用了知名的基准测试工具,但是具体的数据可能并不能精确地说明云服务器的性能。因为云服务器的性能和相邻租户使用情况是相关的,根据其他租户的使用情况而不同,因此以上数据仅作参考使用。

考虑价格因素*后我们来加入价格因素。阿里云此前在云栖大会上宣布云产品大幅降价,近期腾讯云方面也趁着双十一宣布了一轮降价,那么我们结合上面的性能测试结果,来看看降价之后两家的性价比如何。

%title插图%num

上图中的价格信息取自 11 月 4 日创建实例时显示的价格。

从包月费用来看,腾讯云 CVM 比 ECS 要贵那么一丁点,不过考虑到它的性能评分就会觉得贵的物超所值了。但是从之后的二、三年优惠价来看, CVM 的费用反而要低于 ECS 相应期限的成本了。如果两家的降价幅度相同的话,那价格应该是阿里云一直便宜一些才对啊?
确实,背后的原因就是在于二者的降价幅度不同:阿里云是中国区域实例*高 3 年 5 折,带宽和系统盘并没有这么高的折扣,只有 8.5 折。

%title插图%num

相比之下,CVM 是真正的全线降价,三年实例、带宽和系统盘费用都是 5 折优惠。

因此,这段时间内购买腾讯云 CVM 的性价比是要高于阿里云 ECS 的,尤其是购满 2-3 年的话。

云数据库对比我们接着对比两家的基础云数据库: CDB 和 RDS 。

目前虚拟化技术已经取得很大的进展,可以将物理机虚拟化为多个云服务器,而且能做到总体性能的损耗*小。因此,网站的性能差、响应慢,可能不是你的应用代码写的不好,瓶颈很可能就在于云数据库的性能。因此,选择云服务商的云数据库性能,也是决定购买决策的一个重要因素。

由于 MySQL 是网络上使用*为普遍的数据库,腾讯云和阿里云两家基础的数据库产品也都是基于 MySQL 的,因此在这项评测上我们选择 MySQL ,版本为 5.6 。
测试准备工作两家的云数据库目前只提供一种配置类型,分别是高 IO 版( CDB )和双机高可用版( RDS )。因此在这项测试中,使用一组完全相同配置的云数据库是不可能,只能转而使用同价位级别的服务器。

基于上述原因,我们分别在腾讯云和阿里云创建*低配版的云数据库( CDB 和 RDS )。具体配置如下表所示:

%title插图%num

从官方划分的类型和内存大小来看,这应该是一组可比较的实例。另外,为了降低测试时网络的影响,我们继续使用对比云服务器时创建的实例,来运行测试代码。
测试过程MySQL 云数据库有许多性能测试工具,如自带的 mysqlap 。本文所选择的是 sysbench 。

Sysbench 是一个模块化的、跨平台、多线程基准测试工具,主要用于评估测试各种不同系统参数下的数据库负载情况。还可以用来测试 CPU 性能、磁盘 I/O 性能等指标。我们用到的是其提供的 OLTP 基准测试,默认支持 MySQL 数据库。

Sysbench 的安装及测试方法请看云计算产品性能测试指南的云数据库部分。本文中执行了随机读写、随机只读两种测试。

OLTP 测试输出结果如下图所示:

%title插图%num

 

腾讯云 CDB : sysbench 随机只读测试结果

我们需要关注的数据包括测试完成的事务总数,即图中的 read/write requests ,表示数据库的吞吐量;以及平均请求时间,即图中 per-request 数据下的 avg 对应的值,表示数据库请求的延迟。
性能测试结果这里只用到了一种测试工具,而且测试的类型也不多,因此很快我们就可以得到测试结果,将其中我们需要的数据提取出来,可以得到下图中的对比数据。

%title插图%num

从结果可以看出,腾讯云 CDB 的数据库读写请求吞吐量相比 RDS 来说高很多,是后者的约 6-7 倍左右,请求的响应时间也非常快,在 10ms 以内。高 I/O 版本的表现的确强劲。

考虑价格因素*后我们考虑二者的价格因素。

两家*新的优惠价格对比如下:

%title插图%num

以上价格信息取自 11 月 4 日创建实例时显示的价格,区域分别为: CDB 广州, RDS 华南 1

至于另一个费用来源——网络流量费用,如果使用两家对应的云服务器的话,与云数据库之间就是内网流量,应该都是免费的。所以流量费用问题可以忽略。
从上图我们可以得出,两家在包月价格上差异不大,但是就此次降价幅度来看,腾讯云 CDB 的优惠非常之高:二、三年的优惠价( 4 折、 3 折)是 RDS 的一半;一年、二年和三年购买期限处在同一个价位段,而且买两年的价格比一年还低。

如果 Web 应用要求大量快速的数据库读取操作,那么在购买期限为二、三年的情况下,配置两台 CDB 高 IO 版也比选择 RDS 的性价比要高。

如果数据库请求在 RDS 测试结果之内,使用期限也不长,那么可以考虑使用 RDS 。
另外提示一点,虽然说 CDB 的版本介绍为高 I/O 版,但是据官方的产品文档,每一个 CDB 实例都做了实时双机热备,因此在可用性方面的表现应该也不会差太多(这里我们没有对此进行测试)。

对象存储服务对比到*后一个产品了。

对象存储服务的对比有点麻烦,没有比较好用的基准测试工具。在准备测试之前,我发现 Intel 公司开源了一个专门测试云对象存储的工具,叫做 COSBench ,不过可惜的是只支持 Amazon S3 等国外云厂商的服务,不支持腾讯云和阿里云。当然好像可以自己实现对应的适配器,但是对于本文这个较为简单的评测来说,有点太过麻烦了。

因此,在对比对象存储服务时,我使用两家提供的 Python SDK ,编写了测试脚本来统计上传、下载和删除等三个任务的用时。注意,这里并没有测试高并发的情况。
性能测试方法为了控制网络环境对测试结果的影响,我在腾讯云和阿里云各自同区域的云服务器上进行测试,这样不仅测试起来会比较方便,而且能确保测试结果准确有效。我在两家创建的对象存储 Bucket 都是位于华南区的,因此在相应区域分别创建了一台云服务器实例。

同时,为了尽量模拟实际用户的使用场景,我们选择 50KB 、 2MB 、 50MB 三种级别的文件进行测试。一般网络图片的大小在 50K – 2MB 左右,通过这两个级别文件可以测试图片数据存储的效率。另外 50MB级别用于测试大文件存储性能。
具体来说,我们通过 dd 命令生成:

10000 个 50KB 文件

1000 个 20MB 文件

100 个 50MB 文件

 

测试时统计文件上传 /下载 /删除用时等指标,取平均值(单位毫秒)。在测试小文件下载用时时,并没有将文件保存到磁盘,避免了磁盘成为性能瓶颈。
性能测试结果由于测试文件数量不少,整个测试脚本跑下来可能要一个多小时。*终针对 COS 和 OSS 的测试结果(均为单个文件平均值)如下。
50KB 小文件%title插图%num

在 50KB 小文件这个类别中,阿里云 OSS 的上传、删除用时表现不错,小文件下载用时方面腾讯云 COS 用时较少。
2MB 小文件

%title插图%num

 

随着文件大小的增加,腾讯云 COS 在上传、下载用时这两项指标上开始超越 OSS ,差距以倍数计。不过 OSS 在删除用时上仍然保持在 10ms 左右。
50MB 大文件

%title插图%num

由于 50MB 文件的上传、下载、删除用时之间级别相差较大,因此我在绘制图表时将纵轴改为了对数可读,方便阅读。本文测试的实际数据如下表所示:

%title插图%num

在上传大文件时, OSS 与 COS 之间的性能差异显得尤为突出。
综合来看:

阿里云 OSS 在处理文件上传时,随着文件大小增加,性能在逐步下降;下载用时与 COS 相差不大;文件删除用时均优于 COS ,不过文件越大,用时会有对应增加。

腾讯云 COS 在文件上传上的性能比较突出,尤其是大文件;下载用时表现也不错;文件删除虽然总体不及 OSS ,但每类文件删除用时均保持在相同的水平。

如果将三个指标结合在一起,腾讯云 COS 的表现要好于阿里云 OSS 。
考虑价格因素我们接下来看价格因素,以一个想象中的网站示例来对比。

假设一个网站的存储数据有 1.5 TB (图片、音频、视频),每月产生流量 600 GB ,月 PV 大约 300 万,同时每月读请求 600 万次,写请求 30 万次(平均日请求 21 万)。

我们使用上面的网站数据,通过官方提供的价格计算器(COS、OSS)来计算使用 OSS 和 COS 的价格。

由于腾讯云 COS 目前只提供按量计费模式,因此对比的计费方式均选择为按量计费。
结果如所示:

%title插图%num

阿里云 OSS 按量计费价格(区域选择为华南): 616.7 元 /月。

腾讯云 COS 按量计费价格: 593.4 元 /月。

腾讯云*新服务器活动–云服务器免费送。

试用领取有人能领到180天。

腾讯云领取优惠券地址

阿里云领取优惠券地址

上面在计算价格时,并没有加入 CDN 因素。不过两家在介绍产品时都提到了,如果设置 CDN 加速或回源,价格会更低。

腾讯云在上面的计费对比中胜出的原因,可能与其推出的免费额度有关。目前,每个 COS 用户都有每月 50G 的免费存储空间, 10G 的免费流量,以及 100 万次免费读请求和 10 万次免费写请求。阿里云在2015 年时曾推出过免费 OSS 额度,但是目前已经没有了。
结语至此,我们已经完成了对腾讯云和阿里云三个基础性云计算产品的评测对比,兼顾了性能指标和价格因素。具体的评测结果总结如下:

云服务器:同等配置下,腾讯云 CVM 的整体性能高出阿里云 ECS 不少; CVM 的包月费用略高于 ECS ( 3 块钱),但是此次降价幅度比 ECS 更大,一年期以上购买 CVM 的性价比更高。

云数据库:由于二者类别不同,测试了各自*低等级配置的 CDB 和 RDS , CDB 在吞吐量和延迟两项性能指标上均大幅*;同时降价力度也大于 RDS ,因此可以说 CDB 的性价比远高于 RDS 。

对象存储:在大小文件的上传、下载和删除几项指标上,腾讯云 COS 和阿里云 OSS 各有得分, OSS 在文件删除上表现不错,但是在大文件上传上要逊色不少; COS 在各项指标上的表现都可圈可点。

因此,仅仅从这三项产品的性价比来看,腾讯云这次降价进一步增加了其产品的优势。如果让我在这场价格战下选择云计算服务商的话,我会选择腾讯云。而这也是我之前迁移网站时所做的选择。

不过话又说回来,要评估一家云计算厂商,除了性能和价格之外,还要考虑可用性、可靠性等其他诸多指标(各家之间的差异可能不大)。对后者进行评测涉及的操作更为复杂,并不是本文所能涵盖的。而我上面所做的选择,也主要是基于性能和价格两个因素来考虑的。
由于时间有限,无法将国内其他云计算厂商的产品一并加入测试,欢迎有兴趣的朋友按照本文所介绍方法对自己所使用的云计算产品进行测试,并将结果分享给我,方便大家参考。也希望本文能够帮助大家选购到满意的云计算产品。
————————————————

原文链接:https://blog.csdn.net/jianzhandaren/article/details/87911107

linux 安装及卸载vsftp

查看是否安装了vsftp:

rpm -qa |grep vsftp

卸载vsftp

rpm -e vsftp

安装vsftp

yum install -y vsftp

设置vsftp开机启动

chkconfig –list查看不同启动级别自动启动的系统服务

chkconfig –level 35 –add vsftpd on 添加vsftpd自启动以及级别为3和5(关闭为off,具体参照chkconfig)

更改vsftp端口

更改/etc/vsftpd/vsftpd.conf添加listen_port=更改的端口数值

更改/etc/services里的ftp对应的tcp和udp对应端口为更改的端口

TabHost与RadioGroup结合完成的菜单

效果图:
%title插图%num

首先看布局文件:

Java代码
  1. <?xml version=“1.0” encoding=“UTF-8”?>
  2. <TabHost android:id=“@android:id/tabhost” android:layout_width=“fill_parent” android:layout_height=“fill_parent”
  3.   xmlns:android=“http://schemas.android.com/apk/res/android”>
  4.     <LinearLayout
  5.         android:orientation=“vertical”
  6.         android:layout_width=“fill_parent”
  7.         android:layout_height=“fill_parent”>
  8.         <FrameLayout
  9.             android:id=“@android:id/tabcontent”
  10.             android:layout_width=“fill_parent”
  11.             android:layout_height=“0.0dip”
  12.             android:layout_weight=“1.0” />
  13.         <TabWidget
  14.             android:id=“@android:id/tabs”
  15.             android:visibility=“gone”
  16.             android:layout_width=“fill_parent”
  17.             android:layout_height=“wrap_content”
  18.             android:layout_weight=“0.0” />
  19.         <RadioGroup
  20.             android:gravity=“center_vertical”
  21.             android:layout_gravity=“bottom”
  22.             android:orientation=“horizontal”
  23.             android:id=“@+id/main_radio”
  24.             android:background=“@drawable/maintab_toolbar_bg”
  25.             android:layout_width=“fill_parent”
  26.             android:layout_height=“wrap_content”>
  27.             <RadioButton
  28.                 android:id=“@+id/radio_button0”
  29.                 android:tag=“radio_button0”
  30.                 android:layout_marginTop=“2.0dip”
  31.                 android:text=“@string/alarm”
  32.                 android:drawableTop=“@drawable/icon_1”
  33.                 style=“@style/main_tab_bottom” />
  34.             <RadioButton
  35.                 android:id=“@+id/radio_button1”
  36.                 android:tag=“radio_button1”
  37.                 android:layout_marginTop=“2.0dip”
  38.                 android:text=“@string/message”
  39.                 android:drawableTop=“@drawable/icon_2”
  40.                 style=“@style/main_tab_bottom” />
  41.             <RadioButton
  42.                 android:id=“@+id/radio_button2”
  43.                 android:tag=“radio_button2”
  44.                 android:layout_marginTop=“2.0dip”
  45.                 android:text=“@string/photo”
  46.                 android:drawableTop=“@drawable/icon_3”
  47.                 style=“@style/main_tab_bottom” />
  48.             <RadioButton
  49.                 android:id=“@+id/radio_button3”
  50.                 android:tag=“radio_button3”
  51.                 android:layout_marginTop=“2.0dip”
  52.                 android:text=“@string/music”
  53.                 android:drawableTop=“@drawable/icon_4”
  54.                 style=“@style/main_tab_bottom” />
  55.             <RadioButton
  56.                 android:id=“@+id/radio_button4”
  57.                 android:tag=“radio_button4”
  58.                 android:layout_marginTop=“2.0dip”
  59.                 android:text=“@string/setting”
  60.                 android:drawableTop=“@drawable/icon_5”
  61.                 style=“@style/main_tab_bottom” />
  62.         </RadioGroup>
  63.     </LinearLayout>
  64. </TabHost>
[java]  view plain copy

  1. <?xml version=“1.0” encoding=“UTF-8”?>
  2. <TabHost android:id=“@android:id/tabhost” android:layout_width=“fill_parent” android:layout_height=“fill_parent”
  3.   xmlns:android=“http://schemas.android.com/apk/res/android”>
  4.     <LinearLayout
  5.         android:orientation=“vertical”
  6.         android:layout_width=“fill_parent”
  7.         android:layout_height=“fill_parent”>
  8.         <FrameLayout
  9.             android:id=“@android:id/tabcontent”
  10.             android:layout_width=“fill_parent”
  11.             android:layout_height=“0.0dip”
  12.             android:layout_weight=“1.0” />
  13.         <TabWidget
  14.             android:id=“@android:id/tabs”
  15.             android:visibility=“gone”
  16.             android:layout_width=“fill_parent”
  17.             android:layout_height=“wrap_content”
  18.             android:layout_weight=“0.0” />
  19.         <RadioGroup
  20.             android:gravity=“center_vertical”
  21.             android:layout_gravity=“bottom”
  22.             android:orientation=“horizontal”
  23.             android:id=“@+id/main_radio”
  24.             android:background=“@drawable/maintab_toolbar_bg”
  25.             android:layout_width=“fill_parent”
  26.             android:layout_height=“wrap_content”>
  27.             <RadioButton
  28.                 android:id=“@+id/radio_button0”
  29.                 android:tag=“radio_button0”
  30.                 android:layout_marginTop=“2.0dip”
  31.                 android:text=“@string/alarm”
  32.                 android:drawableTop=“@drawable/icon_1”
  33.                 style=“@style/main_tab_bottom” />
  34.             <RadioButton
  35.                 android:id=“@+id/radio_button1”
  36.                 android:tag=“radio_button1”
  37.                 android:layout_marginTop=“2.0dip”
  38.                 android:text=“@string/message”
  39.                 android:drawableTop=“@drawable/icon_2”
  40.                 style=“@style/main_tab_bottom” />
  41.             <RadioButton
  42.                 android:id=“@+id/radio_button2”
  43.                 android:tag=“radio_button2”
  44.                 android:layout_marginTop=“2.0dip”
  45.                 android:text=“@string/photo”
  46.                 android:drawableTop=“@drawable/icon_3”
  47.                 style=“@style/main_tab_bottom” />
  48.             <RadioButton
  49.                 android:id=“@+id/radio_button3”
  50.                 android:tag=“radio_button3”
  51.                 android:layout_marginTop=“2.0dip”
  52.                 android:text=“@string/music”
  53.                 android:drawableTop=“@drawable/icon_4”
  54.                 style=“@style/main_tab_bottom” />
  55.             <RadioButton
  56.                 android:id=“@+id/radio_button4”
  57.                 android:tag=“radio_button4”
  58.                 android:layout_marginTop=“2.0dip”
  59.                 android:text=“@string/setting”
  60.                 android:drawableTop=“@drawable/icon_5”
  61.                 style=“@style/main_tab_bottom” />
  62.         </RadioGroup>
  63.     </LinearLayout>
  64. </TabHost>

需要注意的是,如果用TabHost这个控件,其中有几个ID是必须这么写的,android:id=”@android:id/tabhost   ;android:id=”@android:id/tabcontent” ;android:id=”@android:id/tabs” ;之所以要这么写是因为在TabHost这个类中。需要实例化上述这个ID的控件。看源码:

在TabActivity中有么个方法:

  1. @Override
  2. public void onContentChanged() {
  3.     super.onContentChanged();
  4.     mTabHost = (TabHost) findViewById(com.android.internal.R.id.tabhost);
  5.     if (mTabHost == null) {
  6.         throw new RuntimeException(
  7.                 “Your content must have a TabHost whose id attribute is “ +
  8.                 “‘android.R.id.tabhost'”);
  9.     }
  10.     mTabHost.setup(getLocalActivityManager());
  11. }
  12. private void ensureTabHost() {
  13.     if (mTabHost == null) {
  14.         this.setContentView(com.android.internal.R.layout.tab_content);
  15.     }
  16. }
[java]  view plain copy

  1. @Override
  2. public void onContentChanged() {
  3.     super.onContentChanged();
  4.     mTabHost = (TabHost) findViewById(com.android.internal.R.id.tabhost);
  5.     if (mTabHost == null) {
  6.         throw new RuntimeException(
  7.                 “Your content must have a TabHost whose id attribute is “ +
  8.                 “‘android.R.id.tabhost'”);
  9.     }
  10.     mTabHost.setup(getLocalActivityManager());
  11. }
  12. private void ensureTabHost() {
  13.     if (mTabHost == null) {
  14.         this.setContentView(com.android.internal.R.layout.tab_content);
  15.     }
  16. }

当内容发生改变时它会调用这个方法,来更新列表或者其他视图,而这个方法中需要实例化TabHost,所以必须通过ID为tabhost实例化。

再看看TabHost这个类中,

Java代码
  1. public void setup() {
  2.     mTabWidget = (TabWidget) findViewById(com.android.internal.R.id.tabs);
  3.     if (mTabWidget == null) {
  4.         throw new RuntimeException(
  5.                 “Your TabHost must have a TabWidget whose id attribute is ‘android.R.id.tabs'”);
  6.     }
  7.     // KeyListener to attach to all tabs. Detects non-navigation keys 
  8.     // and relays them to the tab content. 
  9.     mTabKeyListener = new OnKeyListener() {
  10.         public boolean onKey(View v, int keyCode, KeyEvent event) {
  11.             switch (keyCode) {
  12.                 case KeyEvent.KEYCODE_DPAD_CENTER:
  13.                 case KeyEvent.KEYCODE_DPAD_LEFT:
  14.                 case KeyEvent.KEYCODE_DPAD_RIGHT:
  15.                 case KeyEvent.KEYCODE_DPAD_UP:
  16.                 case KeyEvent.KEYCODE_DPAD_DOWN:
  17.                 case KeyEvent.KEYCODE_ENTER:
  18.                     return false;
  19.             }
  20.             mTabContent.requestFocus(View.FOCUS_FORWARD);
  21.             return mTabContent.dispatchKeyEvent(event);
  22.         }
  23.     };
  24.     mTabWidget.setTabSelectionListener(new TabWidget.OnTabSelectionChanged() {
  25.         public void onTabSelectionChanged(int tabIndex, boolean clicked) {
  26.             setCurrentTab(tabIndex);
  27.             if (clicked) {
  28.                 mTabContent.requestFocus(View.FOCUS_FORWARD);
  29.             }
  30.         }
  31.     });
  32.     mTabContent = (FrameLayout) findViewById(com.android.internal.R.id.tabcontent);
  33.     if (mTabContent == null) {
  34.         throw new RuntimeException(
  35.                 “Your TabHost must have a FrameLayout whose id attribute is “
  36.                         + “‘android.R.id.tabcontent'”);
  37.     }
  38. }
[java]  view plain copy

  1. public void setup() {
  2.     mTabWidget = (TabWidget) findViewById(com.android.internal.R.id.tabs);
  3.     if (mTabWidget == null) {
  4.         throw new RuntimeException(
  5.                 “Your TabHost must have a TabWidget whose id attribute is ‘android.R.id.tabs'”);
  6.     }
  7.     // KeyListener to attach to all tabs. Detects non-navigation keys
  8.     // and relays them to the tab content.
  9.     mTabKeyListener = new OnKeyListener() {
  10.         public boolean onKey(View v, int keyCode, KeyEvent event) {
  11.             switch (keyCode) {
  12.                 case KeyEvent.KEYCODE_DPAD_CENTER:
  13.                 case KeyEvent.KEYCODE_DPAD_LEFT:
  14.                 case KeyEvent.KEYCODE_DPAD_RIGHT:
  15.                 case KeyEvent.KEYCODE_DPAD_UP:
  16.                 case KeyEvent.KEYCODE_DPAD_DOWN:
  17.                 case KeyEvent.KEYCODE_ENTER:
  18.                     return false;
  19.             }
  20.             mTabContent.requestFocus(View.FOCUS_FORWARD);
  21.             return mTabContent.dispatchKeyEvent(event);
  22.         }
  23.     };
  24.     mTabWidget.setTabSelectionListener(new TabWidget.OnTabSelectionChanged() {
  25.         public void onTabSelectionChanged(int tabIndex, boolean clicked) {
  26.             setCurrentTab(tabIndex);
  27.             if (clicked) {
  28.                 mTabContent.requestFocus(View.FOCUS_FORWARD);
  29.             }
  30.         }
  31.     });
  32.     mTabContent = (FrameLayout) findViewById(com.android.internal.R.id.tabcontent);
  33.     if (mTabContent == null) {
  34.         throw new RuntimeException(
  35.                 “Your TabHost must have a FrameLayout whose id attribute is “
  36.                         + “‘android.R.id.tabcontent'”);
  37.     }
  38. }

这个方法,是在增加选项卡之前由系统调用。在这个方法中需要通过tabs 这个ID实例化一个TabWidget,通过tabcontent这个ID实例化一个FrameLayout,用来放置选项卡内容。所以这两个ID也是固定的。

在上述布局文件中隐藏了系统默认的Widget,取而代之的是带有图片的Button。

看一下主要代码:

Java代码
  1. package com.iteye.androidtoast;
  2. import android.app.TabActivity;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. import android.widget.RadioGroup;
  6. import android.widget.RadioGroup.OnCheckedChangeListener;
  7. import android.widget.TabHost;
  8. public class MainActivity extends TabActivity implements OnCheckedChangeListener{
  9.     /** Called when the activity is first created. */
  10.     private TabHost mHost;
  11.     private RadioGroup radioderGroup;
  12.     @Override
  13.     public void onCreate(Bundle savedInstanceState) {
  14.         super.onCreate(savedInstanceState);
  15.         setContentView(R.layout.maintabs);
  16.         //实例化TabHost 
  17.         mHost=this.getTabHost();
  18.         //添加选项卡 
  19.         mHost.addTab(mHost.newTabSpec(“ONE”).setIndicator(“ONE”)
  20.                     .setContent(new Intent(this,OneActivity.class)));
  21.         mHost.addTab(mHost.newTabSpec(“TWO”).setIndicator(“TWO”)
  22.                 .setContent(new Intent(this,TwoActivity.class)));
  23.         mHost.addTab(mHost.newTabSpec(“THREE”).setIndicator(“THREE”)
  24.                 .setContent(new Intent(this,ThreeActivity.class)));
  25.         mHost.addTab(mHost.newTabSpec(“FOUR”).setIndicator(“FOUR”)
  26.                 .setContent(new Intent(this,FourActivity.class)));
  27.         mHost.addTab(mHost.newTabSpec(“FIVE”).setIndicator(“FIVE”)
  28.                 .setContent(new Intent(this,FiveActivity.class)));
  29.         radioderGroup = (RadioGroup) findViewById(R.id.main_radio);
  30.         radioderGroup.setOnCheckedChangeListener(this);
  31.     }
  32.     @Override
  33.     public void onCheckedChanged(RadioGroup group, int checkedId) {
  34.         switch(checkedId){
  35.         case R.id.radio_button0:
  36.             mHost.setCurrentTabByTag(“ONE”);
  37.             break;
  38.         case R.id.radio_button1:
  39.             mHost.setCurrentTabByTag(“TWO”);
  40.             break;
  41.         case R.id.radio_button2:
  42.             mHost.setCurrentTabByTag(“THREE”);
  43.             break;
  44.         case R.id.radio_button3:
  45.             mHost.setCurrentTabByTag(“FOUR”);
  46.             break;
  47.         case R.id.radio_button4:
  48.             mHost.setCurrentTabByTag(“FIVE”);
  49.             break;
  50.         }
  51.     }
  52. }
[java]  view plain copy

  1. package com.iteye.androidtoast;
  2. import android.app.TabActivity;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. import android.widget.RadioGroup;
  6. import android.widget.RadioGroup.OnCheckedChangeListener;
  7. import android.widget.TabHost;
  8. public class MainActivity extends TabActivity implements OnCheckedChangeListener{
  9.     /** Called when the activity is first created. */
  10.     private TabHost mHost;
  11.     private RadioGroup radioderGroup;
  12.     @Override
  13.     public void onCreate(Bundle savedInstanceState) {
  14.         super.onCreate(savedInstanceState);
  15.         setContentView(R.layout.maintabs);
  16.         //实例化TabHost
  17.         mHost=this.getTabHost();
  18.         //添加选项卡
  19.         mHost.addTab(mHost.newTabSpec(“ONE”).setIndicator(“ONE”)
  20.                     .setContent(new Intent(this,OneActivity.class)));
  21.         mHost.addTab(mHost.newTabSpec(“TWO”).setIndicator(“TWO”)
  22.                 .setContent(new Intent(this,TwoActivity.class)));
  23.         mHost.addTab(mHost.newTabSpec(“THREE”).setIndicator(“THREE”)
  24.                 .setContent(new Intent(this,ThreeActivity.class)));
  25.         mHost.addTab(mHost.newTabSpec(“FOUR”).setIndicator(“FOUR”)
  26.                 .setContent(new Intent(this,FourActivity.class)));
  27.         mHost.addTab(mHost.newTabSpec(“FIVE”).setIndicator(“FIVE”)
  28.                 .setContent(new Intent(this,FiveActivity.class)));
  29.         radioderGroup = (RadioGroup) findViewById(R.id.main_radio);
  30.         radioderGroup.setOnCheckedChangeListener(this);
  31.     }
  32.     @Override
  33.     public void onCheckedChanged(RadioGroup group, int checkedId) {
  34.         switch(checkedId){
  35.         case R.id.radio_button0:
  36.             mHost.setCurrentTabByTag(“ONE”);
  37.             break;
  38.         case R.id.radio_button1:
  39.             mHost.setCurrentTabByTag(“TWO”);
  40.             break;
  41.         case R.id.radio_button2:
  42.             mHost.setCurrentTabByTag(“THREE”);
  43.             break;
  44.         case R.id.radio_button3:
  45.             mHost.setCurrentTabByTag(“FOUR”);
  46.             break;
  47.         case R.id.radio_button4:
  48.             mHost.setCurrentTabByTag(“FIVE”);
  49.             break;
  50.         }
  51.     }
  52. }