前言
在上次的博客中,我们分析了如果扫描图书的ISBN码后,所进行的处理操作。但是对于其中连接网络,打开网页URL的部分并没有展开分析。这部分功能主要是通过一个叫作 HttpHelper 的类来实现的,因此本次代码分析将以其为重点展开。
一、HttpURLConnection
在Android开发中网络请求是最常用的操作之一, Android SDK中对HTTP也提供了很好的支持,其中就包括标准Java接口(java.NET) —-HttpURLConnection,可以实现简单的基于URL请求、响应功能
HttpURLConnection的使用步骤:
对于HttpURLConnection的理解:
- 任何网络连接都需要经过Socket才能连接,HttpURLConnection使用中并没有设置Socket,所以说HttpURLConnection并不是底层的连接,而是在底层连接上的一个请求
- 虽然底层的网络连接可以被多个HttpURLConnection实例共享,但每一个HttpURLConnection实例只能发送一个请求。请求结束之后,应该调用HttpURLConnection实例的 InputStream 或 OutputStream的close() 方法以释放请求的网络资源。不过对于持久化连接,需要用 disconnect() 方法关闭底层连接的socket。
- HttpURLConnection 只是一个抽象类,只能通过 url.openConection() 方法创建具体的实例。严格来说,openConection() 方法返回的是 URLConnection 的子类。根据 url 对象的不同,如可能不是 http:// 开头的,那么 openConection() 返回的可能就不是 HttpURLConnection
二、代码分析
在全局代码中,一共有多处使用到了 HttpHelper,这些调用类都涉及根据URL打开网页的操作,而其中调用了 HttpHelper 的方法 downloadViaHttp(String uri, ContentType type),来获取网页请求结果
downloadViaHttp
在 HttpHelper 中,downloadViaHttp 进行了方法重载,外部类调用的方法都是
public static CharSequence downloadViaHttp(String uri, ContentType type) throws IOException {
return downloadViaHttp(uri, type, Integer.MAX_VALUE);
}
其中参数分别为:
参数 | 含义 |
---|
uri | 检索的URL地址 | type | ContentType类是HTTP支持的内容类型,有:HTML/JSON/XML/TEXT |
重载的方法多了一个参数 int maxChars 来表示读取到的最大字符数,在该方法中,其根据 ContentType ,来将不同类型解析为了字符串格式,以便提交
public static CharSequence downloadViaHttp(String uri, ContentType type, int maxChars) throws IOException {
String contentTypes;
switch (type) {
case HTML:
contentTypes = "application/xhtml+xml,text/html,text/*,*/*";
break;
case JSON:
contentTypes = "application/json,text/*,*/*";
break;
case XML:
contentTypes = "application/xml,text/*,*/*";
break;
default:
contentTypes = "text/*,*/*";
}
return downloadViaHttp(uri, contentTypes, maxChars);
}
而最后调用的 downloadViaHttp 方法,则真正的进行了网络请求
private static CharSequence downloadViaHttp(String uri, String contentTypes, int maxChars) throws IOException
其首先创建了URL对象,而后获取 HttpURLConnection 对象实例,这里的 safelyOpenConnection 继承了 HttpURLConnection,其主要是一些异常处理操作,来排除建立的对象非 HttpURLConnection 实例的情况(如果 url 不是 http:// 开头的,那么 openConection() 返回的可能就不是 HttpURLConnection)
URL url = new URL(uri);
HttpURLConnection connection = safelyOpenConnection(url);
创建对象后,需要设置 http 请求头;同时设置所有的 http 连接自动处理重定向
connection.setInstanceFollowRedirects(true);
connection.setRequestProperty("Accept", contentTypes);
connection.setRequestProperty("Accept-Charset", "utf-8,*");
connection.setRequestProperty("User-Agent", "ZXing (Android)");
而后获取状态码
int responseCode = safelyConnect(connection);
根据状态码不同进行不同的操作: 对于 HttpURLConnection.HTTP_MOVED_TEMP 的情况:
case HttpURLConnection.HTTP_MOVED_TEMP:
String location = connection.getHeaderField("Location");
if (location != null) {
uri = location;
redirects++;
continue;
}
throw new IOException("No Location");
这里需要注意重定向的页面不能过多,在方法一开始也进行了限制
private static CharSequence downloadViaHttp(String uri, String contentTypes, int maxChars) throws IOException {
int redirects = 0;
while (redirects < 5) {
......
}
throw new IOException("Too many redirects");
}
对于 HttpURLConnection.HTTP_OK 的情况: 其调用了 consume 方法,来获得服务器返回的输入流,并将其作为结果返回
private static CharSequence consume(URLConnection connection, int maxChars) throws IOException {
String encoding = getEncoding(connection);
StringBuilder out = new StringBuilder();
try (Reader in = new InputStreamReader(connection.getInputStream(), encoding)) {
char[] buffer = new char[1024];
int charsRead;
while (out.length() < maxChars && (charsRead = in.read(buffer)) > 0) {
out.append(buffer, 0, charsRead);
}
}
return out;
}
总结
通过本次代码分析,了解了Zxing项目在处理URL请求时的操作,同时熟悉了Android开发中网络请求的流程。到这里,整个 Zxing 项目有关结果处理的重点部分就基本分析完了。接下来将会把重点放在在 Zxing 安卓端使用编码功能所进行的处理操作
|