个人信息

  • 金思宇/男/1991
  • 手机:15651738597      Email:1192937986@qq.com     QQ:1192937986
  • 南京邮电大学 物联网 硕士(2016应届生)
  • Github: https://github.com/njuptjsy/
  • 期望职位:Android开发工程师
  • 期望城市:南京 杭州 上海

教育经历

物联网(物流工程) 南京邮电大学

2013.9至2016.4 |硕士研究生丨GPA:3.5丨班级名次:前5名
本专业主要研究计算机软件技术在信息产业及通信领域中的应用,主要课程包括计算机网络软件、通信网安全、通信协议的测试以及电子商务等

广播电视工程 南京邮电大学

2009.9至2013.6 |本科丨GPA:3.1 | 班级名次:前20名
本专业是以视音频技术为核心,并与计算机科学、通信技术、网络技术、视听艺术等学科融合的复合型专业


实习经历

阿尔卡特朗讯  软件开发工程师  2014.7至2015.4

参与中国区模式创新重点项目ThinkBox,独立开发了2X50BBU 模块和Soc 模块(中国移动4G 基站主要模块)的检测逻辑以及蓝牙打印、重置路由器、更新配置文件和上传日志等功能。负责维护公司服务服务器上的一个脚本程序用于在JIRA 和Case 系统中同步任务信息个人获得ALU wireless Services Quality Award , 团队获得ALU 2014 wireless BL Best Team 称号

ThinkBox 移动应用项目(核心开发人员)
简介:使用Android 设备对基站进行检查,显示基站运行问题,智能提供解决方案,上传日志到云端。项目为公司节省大量成本,目前已在全球范围推广。本人参与项目Android端APP的开发,完整的参与了项目构思、设计、实现、测试到最后发布的整个过程,编写了1/3 的功能模块,带领2名测试人员对APP进行测试,并解决用户反馈的问题。主要界面使用gridView、ListView等
成果:
1.第一个以实习生身份获得 ALU wireless Services Quality Award
2.独立解决了程序对特殊的SoC和2X50BBU模块的支持问题,减少了代码的冗余;
3.根据用户需求独立设计并开发检查结果打印(BlueToothAdapter+热敏打印机SDK)和邮件发送(第三方SDK)模块;
4.设计开发动态加载JS 和XML配置文件的方式将业务逻辑从APP 中分离;
5.设计开发了通过WebView 加载HTML 方式提供问题解决方案;
6.使用Service 后台上传用户数据(修改了第三方SDK 实现数据上传阿里云);
7.修复近二十个用户反馈的Bug,培训测试人员,编写测试脚本(通过Sed/Awk 进行文本对比)

Case 到JIRA 同步脚本项目(维护和修改)
简介:使用Perl 脚本负责将Case 系统中的数据同步到JIRA 看板中;改进脚本,将每天的执行结果以邮件形式发送给相关人员。
成果:添加了发送运行结果到公司邮箱的功能;将脚本添加到crontab 中自动运行;根据部门需求不断修改脚本

Citrix   测试开发工程师   2015.4至今

学习思杰XenMobile系列产品,重现客户问题,和同事一起收集并分析log定位问题。学习思杰的全系列产品架构及组件间通信。
基于XenServer的XenDesktop环境(部署和测试) 2015.7至今
简介:在服务器上部署XenServer对服务器进行虚拟化,基于XenServer部署了XenDesktop的所有组件
成果:在XenServer上搭建了XenDesktop环境,并成功交付了桌面和应用


科研项目

移动云存储客户端(独立开发) 2014.6至今
https://github.com/njuptjsy/mobliecloudapp
简介:研究如何在Android设备上使用各种云平台提供的存储和计算资源,本人开发了云客户端原型,同时实现了在Android设备上存储并简单处理ZigBee数据,使本项目作为连接实验室两个项目的桥梁。
成果:
1.完成了从用例图需求分析到实现类图的设计;
2.通过继承抽象类和实现接口的方式使项目架构清晰;
3.完成了兼容OpenStack、AWS 和阿里云的数据上传下载文件模块;
4.完成了收集移动设备电量、内存和存储等信息的信息采集模块和(使用GitHub开源项目)数据表示;
5.完成了云平台资源使用信息的信息管理模块;
6.完成了用户的邮件反馈的模块
7.完成了Android设备计算减负方案的设计和研究(论文撰写中)

OpenStack 云平台的VM 的资源监测(开发人员) 2013.10至2014.6
简介:江苏省未来网络项目,实时检测云主机资源的利用情况
成果:部署了OpenStack 云平台;按照本地环境改写了网上的部署脚本;形成了OpenStack 部署文档;开发了云主机资源监测工具

自主项目

学生信息系统(独立开发) 2015.2至今
https://github.com/njuptjsy/AgileJavaNote
简介:自学敏捷开发的思想,采用TDD 的方式开发一个学生信息系统
成果:运用了UML 进行类的设计;对JAVA 中大部分的概念和特性动手编程实践;使用JUnit 对每个模块编写测试用例

Android APP Dome(独立开发) 2014.9至今
简介:动手实践了十多个Android项目的用例,包括Android四大组件、多线程、SQLite和网络通信等
成果:利用原生组件和自定义View完整的开发了2048游戏;  在AWS EC2上搭建了openfire服务器,客户端界面使用ViewPager+Fragment实现;使用自定义View实现了底部Button滑动渐变色;实现防微信发送语音界面;通过反射修改了系统原生menu和ActionBar的显示;自定义ListView实现下拉刷新;下一步将使用smack实现即时通讯


技能清单

  • 熟练的技能:Java  Android  C  JUnit
  • 了解的技能:JavaScript  Linux  MySql  HTML  Git
  • 熟悉的操作系统/云平台:Linux\Windows  OpenStack  AWS  阿里云
  • 熟练的开发工具:Eclipse  Matlab  Intellij
  • 其他技能和证书:计算机二级  大学英语六级  12 个月的外企实习经历具有良好的英语交流能力

校内职务

2011-9 至2013-6 大学生艺术团副主席
成功策划并举办OPPO 南邮2011 迎新晚会、OPPO2010 迎新晚会、圣诞晚会、十佳歌手大赛等多项文艺演出活动
2010-9 至2011-6 大学生艺术团语言类节目部部长
负责话剧、礼仪模特和播音主持三个方面的排练和演出,参与学校各个文艺演出。在校话剧比赛中获得一等奖
2010-9 至2011-6 校心理协会外联部部长
代表社团与OPPO、KFC、工商银行有过多次合作,组织了多届心理文化节,与周边多所高校建立了合作关系

校内奖励

校级优秀团员(2012-10) 社会工作先进个人(2011-10) 院级优秀团员(2010-10) 优秀学生干部(2010-10)
社团活动积极分子(2009-10)


优势描述

  • 善于总结和自学(一年时间自己工作学习中记录300余篇笔记,半年时间Github提交100余次)
  • 优秀的沟通能力 优秀的团队成员,热爱计算机科学及技术
  • 健身帮助我获得了强健的体魄,同时磨炼了我的意志品质,阅读和电影丰富了我作为一个工科生的文化生活

致谢

感谢您花时间阅读我的简历,期待有机会在面试中进一步向贵公司介绍自己。

image
如图所示主要分4层
1.运行在Dalvik虚拟机(基于寄存器的java虚拟机,运行速度更快)上的系统应用。

2.应用框架层(framework):包括客户端和服务端
其中,服务端主要组件有:
WmS(管理Window大小调节叠放层次、隐藏或显示)
AmS(管理Activity并负责与应用程序主进程ActivityThread进行通信)
WmS.KeyQ(读取用户的操作,存放在消息队列QueueEvent中)
InputDispatchThread(取出QueueEvent中的消息,分发给应用)
客户端组件有:
ActivityThread:主线程UI线程,一个应用一个,入口是static main
Activity:应用运行的最小单元,一个应用多个
Window:提供通用窗口操作API
PhoneWindow:继承window类,对FrameLayout进行包装并提供操作API
PhoneWindow.DecorVeiw:对普通FrameLayout进行修饰相应特定按键消息
ViewRoot:继承Handler,接收WmS的通知
ViewRoot.V:继承Binder,向WmS提供IPC接口
WindowManage:客户端和WmS之间的代理

3.系统运行库:NDK使用C\C++编写主要是.so文件。主要包括C标准库、OpenGL ES、SQLit、Webkit和Dalvik虚拟机等。

4.linux内核层,包括驱动、内存管理、进程管理、网络协议栈等。

背景

开发CloudClient的阿里云上传下载模块,本来以为可以愉快的使用阿里云的各种封装好的API,没想到刚刚开始开发下载文件就遇到了问题。阿里云并没有提供具体的根据用户名密码列举该用户名下所有Bucket的方法。

通过阅读其官网描述的API,发现可以基于RESTful的架构自己向阿里云服务器发送请求,从响应消息中解析所需要的信息。列举所以用户名下所有Bucket的方式是进行GetService操作需要构造一个格式如下的Http请求报文

1
2
3
4
GET / HTTP/1.1
Host: oss.aliyuncs.com
Date: GMT Date
Authorization: SignatureValue

其他的都不难理解,就唯独其中的签名Authorization: SignatureValue的生成让人费解,光是看阿里云提供的签名生成方法就花了很大精力。

1
2
3
4
5
6
7
8
9
"Authorization: OSS " + Access Key Id + ":" + Signature

Signature = base64(hmac-sha1(AccessKeySecret,
VERB + "\n"
+ CONTENT-MD5 + "\n"
+ CONTENT-TYPE + "\n"
+ DATE + "\n"
+ CanonicalizedOSSHeaders
+ CanonicalizedResource))

花了很长时间研究CONTENT-MD5、CONTENT-TYPE到底是什么,还有给出的例子中明明是先用RFC 2104中定义的HMAC-SHA1方法以Access Key Secret为密钥加密然后再BASE64编码成字符串就可以了,但在下面的Python实现中还用到digest方法计算加密后数据的MD5,到底那个是正确的让人很迷惑。

1
2
3
4
5
6
import base64
import hmac
import sha
h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV",
"PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha)
base64.encodestring(h.digest()).strip()

问题描述

综上所述,在花了很长时间理解阿里云的文档之后,开始实现getService服务。第一步,需要通过HttpClient构建一个HttpGet消息。

1
2
3
4
5
6
7
8
9
10
HttpClient httpClient = new DefaultHttpClient();
String host = "oss.aliyuncs.com";

URI url = URIUtils.createURI("http", host, -1, "/", null, null);//ublic static URI createURI(String scheme,String host,int port,String path,String query,String fragment)
LogUtil.i("QueryAliyun:sendHttpGet", url+"");

HttpGet httpGet = new HttpGet(url);
httpGet.addHeader("Date", getSystemTime());
httpGet.addHeader("Host","oss.aliyuncs.com");
httpGet.addHeader("Authorization", getSignature());

第二步,需要按照文档中描述的方式对本次请求进行加密。问题就出现在这一步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private String getSignature(){
String encryptText = "GET" + "\n"
+ "" + "\n"
+ "" + "\n"
+ getSystemTime() + "\n"
+ ""
+ "/";

String signature = "";
try {
String signatureTemp = ClientUtils.HmacSHA1Encrypt(InfoContainer.ALIYUN_SCRECT_ID, encryptText);

signature = Base64.encodeToString(signatureTemp.getByte(), Base64.DEFAULT).trim();

} catch (Exception e) {
LogUtil.e("QueryAliyun:getSignature", " catch exception in HmacSHA1Encrypt");
e.printStackTrace();
}
String authorization = "OSS " + InfoContainer.ALIYUN_ACCESS_ID + ":" + signature;
return authorization;
}

我将要加密的文本按照指定的算法进行加密,返回加密结果字符串,再使用BASE64方式编码,与服务器通信后始终是403错误。研究了很久,发现使用阿里云提供的方法对同样的内容进行签名操作就可以通信,于是我将该方法的结果进行BASE64解码,发现解码的结果和使用ClientUtils.HmacSHA1Encrypt方法放回的字符串一样。根据这个结论进一步研究猜测问题出现在signatureTemp.getByte()这个方法上,我将加密的结果作为byte[]返回,而不是先转换成字符串在装换成byte数组,再进行BASE64编码就可以正常通信了。

这让我怀疑通过new String()得到的字符串,再进行getByte[]操作无法得到原有的byte数组。因为new String和getByte方法在不指定编码方式的情况下都是使用当前环境的编码方式,这里是UTF-8,于是我使用了下面的方法进行测试

1
2
3
4
5
6
7
8
9
private void testGetbyte(byte[] signatureTemp) {
String testString;
try {
testString = new String(signatureTemp,"UTF-8");
byte[] testBytes = testString.getBytes("UTF-8");
LogUtil.i("QueryAliyun:testGetbyte", signatureTemp + " and " + testBytes);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}

发现在utf-8的编码规则下,将byte数组装换成字符串在将字符串转换成byte数组,源数组不等于操作过后的数组。进一步研究,发现原因是因为UTF-8编码方式并不是采用单字节的编码方式进行转换,如果将这里的编码方式改成ISO-8859-1,源数组就和操作后的得到的数组一致了。这个坑也是导致我在这个地方花费了很长时间。

第三步,解析返回的数据

总结下

这里虽然ISO-8859-1来编码可以解码出原来的byte数组,但是使用不管什么内容,都用new String(…,”ISO-8859-1”)来建立字符串,然后使用的时候按默认的编码格式(通常在服务器上都是英文系统)输出字符串。这样其实你使用的String并不是按UNICODE来代表真正的字符,而是强行把BYTE数组复制到String的char[]里,一旦你的运行环境改变,你就被迫要修改一大堆的代码。而且也无法在同一个字符串里处理几种不同编码的文字。
另一个是把一种编码格式的字符串,比如是GB2312,转换成另一种格式的字符串,比如UTF-8,然后不指明是UTF-8编码,而直接用new String(…)来建立String,这样放在String里面的字符也是无法确定的,它在不同的系统上代表不同的字符。如果要求别人用“UTF-8格式”的String来交换信息的时候,其实已经破坏了JAVA为了兼容各种语言所做的规定。这种错误的本质思想是还按写C语言的方式,把字符串纯粹当作可以自己自由编码的存储器使用,而忽略了JAVA字符串只有一种编码格式。如果真的想自由编码,用byte[]或者char[]就完全了解决问题的了。

这里不得不吐槽下阿里云的Android API,对各项操作的封装不全也就算了,文档中几乎没有说明性的描述,绝大部分函数都没有任何的说明的文字,传入的形参和返回值也只告诉你类型,使用基本靠猜。即使对自己的命名再有信心,几句说明还是应该有的,具体可以看看AWS的API。
image

基本概念

MVC的主要作用是将应用程序的数据和界面分离,其中M表示Model代表模型,V表示view代表界面,C表示控制器控制M和V之间的联系。Android SDK也采用MVC。
当View数据变化时,其通知Controller,由Controller操作Model进行相应的数据操作。将数据和视图分离之后跟换视图和模型是可以不影响对方,更利于程序维护。Android中典型的例子就是各种列表组件作为View(ListView、GridView、Spinner等),各种适配器作为Controller(BaseAdapter、SimpleAdapter、ArrayAdapter、SimpleCousorAdaptr和CousorAdaptr),对于的Model有数组和Cursor等。当Model变化时,调用notifyDataSetChanged方法通知C,C通过getView重新绘制组件内容。

阿里云文档

开发CloudClient的阿里云上传下载模块,本来以为像listBucket可以愉快的使用阿里云的各种封装好的API,没想到刚刚开始开发下载文件就遇到了问题。阿里云并没有提供具体的根据用户名密码列举该用户名下所有Bucket的方法。

通过阅读其官网描述的API,发现可以基于RESTful的架构自己向阿里云服务器发送请求,从响应消息中解析所需要的信息。列举所以用户名下所有Bucket的方式是进行GetService操作需要构造一个格式如下的Http请求报文

1
2
3
4
GET / HTTP/1.1
Host: oss.aliyuncs.com
Date: GMT Date
Authorization: SignatureValue

其他的都不难理解,就唯独其中的签名Authorization: SignatureValue的生成让人费解,光是看阿里云提供的签名生成方法就花了很大精力。

1
2
3
4
5
6
7
8
9
"Authorization: OSS " + Access Key Id + ":" + Signature

Signature = base64(hmac-sha1(AccessKeySecret,
VERB + "\n"
+ CONTENT-MD5 + "\n"
+ CONTENT-TYPE + "\n"
+ DATE + "\n"
+ CanonicalizedOSSHeaders
+ CanonicalizedResource))

花了很长时间研究CONTENT-MD5、CONTENT-TYPE到底是什么,还有给出的例子中明明是先用RFC 2104中定义的HMAC-SHA1方法以Access Key Secret为密钥加密然后再BASE64编码成字符串就可以了,但在下面的Python实现中还用到digest方法计算加密后数据的MD5,到底那个是正确的让人很迷惑。

1
2
3
4
5
6
import base64
import hmac
import sha
h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV",
"PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha)
base64.encodestring(h.digest()).strip()

开发步骤

综上所述,在花了很长时间理解阿里云的文档之后,开始实现getService服务。第一步,需要通过HttpClient构建一个HttpGet消息。

1
2
3
4
5
6
7
8
9
10
HttpClient httpClient = new DefaultHttpClient();
String host = "oss.aliyuncs.com";

URI url = URIUtils.createURI("http", host, -1, "/", null, null);//ublic static URI createURI(String scheme,String host,int port,String path,String query,String fragment)
LogUtil.i("QueryAliyun:sendHttpGet", url+"");

HttpGet httpGet = new HttpGet(url);
httpGet.addHeader("Date", getSystemTime());
httpGet.addHeader("Host","oss.aliyuncs.com");
httpGet.addHeader("Authorization", getSignature());

问题描述

第二步,需要按照文档中描述的方式对本次请求进行加密。问题就出现在这一步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private String getSignature(){
String encryptText = "GET" + "\n"
+ "" + "\n"
+ "" + "\n"
+ getSystemTime() + "\n"
+ ""
+ "/";

String signature = "";
try {
String signatureTemp = ClientUtils.HmacSHA1Encrypt(InfoContainer.ALIYUN_SCRECT_ID, encryptText);

signature = Base64.encodeToString(signatureTemp.getByte(), Base64.DEFAULT).trim();

} catch (Exception e) {
LogUtil.e("QueryAliyun:getSignature", " catch exception in HmacSHA1Encrypt");
e.printStackTrace();
}
String authorization = "OSS " + InfoContainer.ALIYUN_ACCESS_ID + ":" + signature;
return authorization;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**  
* 使用 HMAC-SHA1 签名方法对对encryptText进行签名
* @param encryptText 被签名的字符串
* @param encryptKey 密钥
* @return 前面后的byte数组
* @throws Exception
*/

public static String HmacSHA1Encrypt(String encryptKey,String encryptText) throws Exception
{

String macMethod = "HmacSHA1";
String encoding = "UTF-8";
byte[] keyBytes=encryptKey.getBytes(encoding);
SecretKey secretKey = new SecretKeySpec(keyBytes, macMethod);//根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
Mac mac = Mac.getInstance(macMethod);//生成一个指定 Mac算法 的 Mac对象
mac.init(secretKey);//用给定密钥初始化 Mac 对象
byte[] text = encryptText.getBytes(encoding);
return new String(mac.doFinal(text));
}

我将要加密的文本按照指定的算法进行加密,返回加密结果字符串,再使用BASE64方式编码,与服务器通信后始终是403错误。研究了很久,发现使用阿里云提供的方法对同样的内容进行签名操作就可以通信,于是我将该方法的结果进行BASE64解码,发现解码的结果和使用ClientUtils.HmacSHA1Encrypt方法放回的字符串一样。根据这个结论进一步研究猜测问题出现在signatureTemp.getByte()这个方法上,我将加密的结果作为byte[]返回,而不是先转换成字符串在装换成byte数组,再进行BASE64编码就可以正常通信了。

这让我怀疑通过new String()得到的字符串,再进行getByte[]操作无法得到原有的byte数组。因为new String和getByte方法在不指定编码方式的情况下都是使用当前环境的编码方式,这里是UTF-8,于是我使用了下面的方法进行测试

1
2
3
4
5
6
7
8
9
private void testGetbyte(byte[] signatureTemp) {
String testString;
try {
testString = new String(signatureTemp,"UTF-8");
byte[] testBytes = testString.getBytes("UTF-8");
LogUtil.i("QueryAliyun:testGetbyte", signatureTemp + " and " + testBytes);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}

发现在utf-8的编码规则下,将byte数组装换成字符串在将字符串转换成byte数组,源数组不等于操作过后的数组。进一步研究,发现原因是因为UTF-8编码方式并不是采用单字节的编码方式进行转换,如果将这里的编码方式改成ISO-8859-1,源数组就和操作后的得到的数组一致了。这个坑也是导致我在这个地方花费了很长时间。

第三步,解析返回的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try {
HttpResponse httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode() == 200) {

HttpEntity entity = httpResponse.getEntity();
String result = EntityUtils.toString(entity,"UTF-8");
LogUtil.i("alyunQuery:sendHttpGet", result);
parseXMLWithPull(result);
}
else {
LogUtil.e("alyunQuery:sendHttpGet", "response wrong stauts code:"+ httpResponse.getStatusLine().getStatusCode());
}
} catch (Exception e) {
e.printStackTrace();
}

首先,校验状态码是否正常为200,接着取出相应消息中的响应体,这里的相应体内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<ListAllMyBucketsResult>
<Owner>
<ID>1173032044021568</ID>
<DisplayName>1173032044021568</DisplayName>
</Owner>
<Buckets>
<Bucket>
<Location>oss-cn-beijing</Location>
<Name>njuptjsy</Name>
<CreationDate>2015-05-23T04:06:57.000Z</CreationDate>
</Bucket>
</Buckets>
</ListAllMyBucketsResult>

可以看到服务器发回的消息中包含在Buckets标签,其中用每个子标签bucket包含了相应的bucket的位置、名称、和创建时间信息。下面只需要将开放需要的名称信息提取出来保存在列表中即可。Android对xml的解析在Android中一共有三种方法:
1.SAX解析XML文件采用的是事件驱动,也就是说,他读取每个标签并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读取到的字符是否符合XML语法中的某部分,如果符合就会触发事件,其实就是一些回调方法,然后进行判断处理。其优点是解析速度快,占用内存少,适用于Android等移动设备,缺点是对于嵌套多个分支的XML文件来说处理不是很方便。

2.DOM解析XML文件时,会将XML文件的所有内容以文档树方式存放在内存中,然后使用DOM API遍历XML树,检索所需的数据,主要用于PC机。其优点是使用DOM解析XML的代码比较直观,相比于基于SAX的实现更加简单,缺点是须将XML文件所有内容存放在内存中,所以消耗内存大,不适用Android等移动设备。

3.Pull解析器是Android内置解析XML文件的解析器,运行方式类似于SAX解析,只是产生的事件是一个数字,而非方法,因此可以使用一个switch对感兴趣的事件进行处理。Pull解析器对节点处理比较好,同样也很省内存,官方推挤使用Pull解析器解析XML文件,而且Android系统本身用到的XML文件内部也是使用Pull解析器进行解析的。这里选用的Pull方法进行解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private void parseXMLWithPull(String result) {
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(new StringReader(result));
int eventType = xmlPullParser.getEventType();

String name = "";
String location = "";
bucketNames = new ArrayList<String>();
while (eventType != XmlPullParser.END_DOCUMENT) {
String nodeName = xmlPullParser.getName();
switch (eventType) {
case XmlPullParser.START_TAG:
if ("Location".equals(nodeName)) {
location = xmlPullParser.nextText();
}
else if ("Name".equals(nodeName)){
name = xmlPullParser.nextText();
}
break;
case XmlPullParser.END_TAG:
if ("Bucket".equals(nodeName)) {
bucketNames.add(name);
LogUtil.i("alyunQuery:parseXMLWithPull", "get name :" + name);
}
break;
default:
break;
}
eventType = xmlPullParser.next();
}
} catch (Exception e) {
e.printStackTrace();
LogUtil.e("alyunQuery:parseXMLWithPull", "parse XML error");
}
}

在parseXMLWithPull函数中,通过工程方法生成xmlPullParser对象对传入的带解析的流进行解析。pull解析在遇到不同的XML标签时会触发不同的事件,如这里用到的遇到标签的起始事件XmlPullParser.START_TAG、遇到标签的结束事件XmlPullParser.END_TAG和遇到XML文件结束标签事件XmlPullParser.END_DOCUMENT。

总结下

这里虽然ISO-8859-1来编码可以解码出原来的byte数组,但是使用不管什么内容,都用new String(…,”ISO-8859-1”)来建立字符串,然后使用的时候按默认的编码格式(通常在服务器上都是英文系统)输出字符串。这样其实你使用的String并不是按UNICODE来代表真正的字符,而是强行把BYTE数组复制到String的char[]里,一旦你的运行环境改变,你就被迫要修改一大堆的代码。而且也无法在同一个字符串里处理几种不同编码的文字。
另一个是把一种编码格式的字符串,比如是GB2312,转换成另一种格式的字符串,比如UTF-8,然后不指明是UTF-8编码,而直接用new String(…)来建立String,这样放在String里面的字符也是无法确定的,它在不同的系统上代表不同的字符。如果要求别人用“UTF-8格式”的String来交换信息的时候,其实已经破坏了JAVA为了兼容各种语言所做的规定。这种错误的本质思想是还按写C语言的方式,把字符串纯粹当作可以自己自由编码的存储器使用,而忽略了JAVA字符串只有一种编码格式。如果真的想自由编码,用byte[]或者char[]就完全了解决问题的了。

这里不得不吐槽下阿里云的Android API,对各项操作的封装不全也就算了,文档中几乎没有说明性的描述,绝大部分函数都没有任何的说明的文字,传入的形参和返回值也只告诉你类型,使用基本靠猜。即使对自己的命名再有信心,几句说明还是应该有的,具体可以看看AWS的API。
image