Android 中的网络操作(HttpURLConnection)
segmentfault 对 mackdown 语法的支持不是很好,有些图片都显示不出来,大家可以去我的掘金查看这篇文章。
一、Android 网络知识简介
Android 程序最重要的模块就是网络部分,如何从网络上下载数据,如何将处理过的数据上传至网络,往往是 Android 程序的关键环节。Android 中对于网络操作的有很多很好用的框架,如 OkHttp、Velloy、Retrofit 等。但是今天我们来重点讲解一下 HttpURLConnection 这个抽象类。
二、利用 HttpURLConnection 实现 Get 和 Post 请求
1、权限申请
Android 中要做跟网络相关的操作,一定需要在清单文件中申请网络权限,如下所示:
Android 9.0 之前,只需要在清单文件中加上这句话就可以了,但是Android 9.0对 http 请求进行了限制,所以仅仅上面这一句话是不够的。为了解除这个限制,我们需要创建安全配置文件,具体步骤如下:
- 在 res 文件夹下创建xml/network-security-config 文件
增加 cleartextTrafficPermitted 属性
<?xml version="1.0" encoding="utf-8"?>
在 AndroidManifest.xml 的 Application 节点中申请
android:networkSecurityConfig="@xml/network_security_config"
2、get 请求
我们从玩Android上面随便找一个 GET 请求的 API。json 数据格式如下所示:
现在我们来利用 HttpURLConnection 的 GET 请求来将上面这段 json 数据打印出来,具体代码如下所示:
private final String URL = "https://wanandroid.com/wxarticle/chapters/json"; // HttpURLConnectionprivate void get() { try { // 1.实例化一个URL对象 URL url = new URL(URL); // 2.获取HttpURLConnection实例 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 3.设置和请求相关的属性 // 请求方式 conn.setRequestMethod("GET"); // 请求超时时间 conn.setConnectTimeout(10 * 1000); // 4.获取响应码 200:成功 404:未请求到指定资源 500:服务器异常 if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { // 5.判断响应码并获取响应数据(响应的正文) // 获取响应的流 // IO 操作 InputStream in = conn.getInputStream(); byte[] b = new byte[1024]; int len; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while ((len = in.read(b)) > -1) { baos.write(b, 0, len); } String msg = baos.toString(); Log.e("MainActivityTAG", msg); } } catch (Exception e) { e.printStackTrace(); }}public void myClick(View v) { switch (v.getId()) { // Android4.0 以后网络操作必须放在子线程中 case R.id.btn_get: new Thread(){ @Override public void run() { super.run(); get(); } }.start(); break; }}
控制台上面的数据如下,我们已经成功的打印出来了。
通过上述代码我们需要注意一下三点:
- 在清单文件中申请 INTERNET 权限
- 如果是 http 请求,需要创建安全配置文件 network-security-config
- Android4.0 以后网络操作必须放在子线程中
3、post 请求
我们从玩Android上面找一个 POST 请求的 API。然后我们可以利用 HttpURLConnection 的 POST 请求来实现一个登陆功能。
具体代码实现如下所示:
private void post(String account, String password) { try { // 1.实例化一个URL对象 URL url = new URL("https://www.wanandroid.com/user/login"); // 2.获取HttpURLConnection实例 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 3.设置和请求相关的属性 // 请求方式 conn.setRequestMethod("POST"); // 请求超时时间 conn.setConnectTimeout(10 * 1000); // 设置允许输出 conn.setDoOutput(true); // 设置提交数据的类型 conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); //获取输出流(请求正文) OutputStream out = conn.getOutputStream(); //写数据 out.write(("username=" + account + "&password=" + password).getBytes()); //4.获取响应码 200:成功 404:未请求到指定资源 500:服务器异常 if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { //5.判断响应码并获取响应数据(响应的正文) //获取响应的流 InputStream in = conn.getInputStream(); byte[] b = new byte[1024]; int len; ByteArrayOutputStream baos = new ByteArrayOutputStream(); //在循环中读取输入流 // in.read(b); // 该方法返回值是int类型数据,代表的是实际读到的数据长度 while ((len = in.read(b)) > -1) { //将字节数组里面的内容存/写入缓存流 //参数1:待写入的数组 //参数2:起点 //参数3:长度 baos.write(b, 0, len); } String msg = new String(baos.toByteArray()); Log.e("MainActivityTAG", msg); } } catch (Exception e) { e.printStackTrace(); }}public void myClick(View v) { switch (v.getId()) { // Android4.0 以后网络操作必须放在子线程中 case R.id.btn_post: final String account = etAccount.getText().toString().trim(); final String password = etPassword.getText().toString().trim(); new Thread() { @Override public void run() { super.run(); post(account, password); } }.start(); break; }}
控制台上面的数据如下,我们已经成功的登陆了。
三、JSON 数据解析
Json 是一种轻量级的数据交互格式,具有良好的可读和便于快速编写的特性。业内主流结束为其提供了完整的解决方案(有点类似于正则表达式,获得了当今大部分语言的支持),从而可以在不同平台间进行数据交换。
1、利用JSONObject 解析
现在我们要在以上 JSON 数据中解析出 "郭霖" 这个字符串,利用 JSONObject 要怎么做呢?
具体解析的方法如下:
JSONObject jsonObject = new JSONObject(str);final int errorCode = jsonObject.getInt("errorCode");final String errorMsg = jsonObject.getString("errorMsg");final String name = jsonObject.getJSONArray("data").getJSONObject(1).getString("name");
首先要获取 data 列表,然后获取第二个对象,在第二个对象中获取 name 属性对应的值就可以了。
具体的效果如下所示:
完整代码如下:
private void paresByJSONObject() { new Thread(){ @Override public void run() { super.run(); String str = get(); // 解析 // JSONObject // 参数:满足 Json 格式要求的字符串 try { if (str != null) { JSONObject jsonObject = new JSONObject(str); final int errorCode = jsonObject.getInt("errorCode"); final String errorMsg = jsonObject.getString("errorMsg"); final String name = jsonObject.getJSONArray("data").getJSONObject(1).getString("name"); runOnUiThread(new Runnable() { @Override public void run() { tv1.setText("errorCode: " + errorCode); tv2.setText(name); } }); } } catch (JSONException e) { e.printStackTrace(); } } }.start();}private String get() { try { // 1.实例化一个URL对象 URL url = new URL("https://wanandroid.com/wxarticle/chapters/json"); // 2.获取HttpURLConnection实例 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 3.设置和请求相关的属性 // 请求方式 conn.setRequestMethod("GET"); // 请求超时时间 conn.setConnectTimeout(10 * 1000); // 4.获取响应码 200:成功 404:未请求到指定资源 500:服务器异常 if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { // 5.判断响应码并获取响应数据(响应的正文) // 获取响应的流 // IO 操作 InputStream in = conn.getInputStream(); byte[] b = new byte[1024]; int len; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while ((len = in.read(b)) > -1) { baos.write(b, 0, len); } return baos.toString(); } } catch (Exception e) { e.printStackTrace(); } return null;}
2、利用 GSON 解析
可以看到,用 JSONObject 解析 json数据相对来说是比较麻烦的,所以在日常工作中我们是不会用 JSONObject 去解析的。目前比较流行的 json解析工具有 gson,jackson,fastjson 等。这里我们就挑 gson来简单讲解一下吧。
1)、将对象转成 json 字符串(toJson )
我能根据上面的一个 JSON 数据创建一个对象 Wxarticle。
public class Wxarticle { private int courseId; private int id; private String name; private int order; private int parentChapterId; private boolean userControlSetTop; private int visible; public Wxarticle() { } public Wxarticle(int courseId, int id, String name, int order, int parentChapterId, boolean userControlSetTop, int visible) { this.courseId = courseId; this.id = id; this.name = name; this.order = order; this.parentChapterId = parentChapterId; this.userControlSetTop = userControlSetTop; this.visible = visible; } public int getCourseId() { return courseId; } public void setCourseId(int courseId) { this.courseId = courseId; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getOrder() { return order; } public void setOrder(int order) { this.order = order; } public int getParentChapterId() { return parentChapterId; } public void setParentChapterId(int parentChapterId) { this.parentChapterId = parentChapterId; } public boolean isUserControlSetTop() { return userControlSetTop; } public void setUserControlSetTop(boolean userControlSetTop) { this.userControlSetTop = userControlSetTop; } public int getVisible() { return visible; } public void setVisible(int visible) { this.visible = visible; } @Override public String toString() { return "wxarticle{" + "courseId=" + courseId + ", id=" + id + ", name='" + name + '\'' + ", order=" + order + ", parentChapterId=" + parentChapterId + ", userControlSetTop=" + userControlSetTop + ", visible=" + visible + '}'; }}
Gson 的 toJson 方法就是将一个对象转成 Json 字符串。我们来调用这个方法试一下。
Gson gson = new Gson();// 将对象变成 json 字符串Wxarticle wxarticle = new Wxarticle(13, 408, "鸿洋", 190000, 407, false, 1);String str = gson.toJson(wxarticle);Log.e("JSONActivity", str);
我们可以看到,对象已经成功的转成 Json 字符串了。
2)、将 json 字符串转成对象(fromJson)
我们利用 fromJson 方法将上述 json 对象中的 name 都输出出来,我们需要创建一个 Test 对象,具体代码如下所示:
public class Test { private List data; private int errorCode; private String errorMsg; public Test() { } public Test(List data, int errorCode, String errorMsg) { this.data = data; this.errorCode = errorCode; this.errorMsg = errorMsg; } public List getData() { return data; } public void setData(List data) { this.data = data; } public int getErrorCode() { return errorCode; } public void setErrorCode(int errorCode) { this.errorCode = errorCode; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; }}
具体解析代码如下所示:
// fromJsonnew Thread(){ @Override public void run() { super.run(); String str = get(); Test test = gson.fromJson(str, Test.class); for (int i = 0; i < test.getData().size(); i++) { Log.e("JSONActivityTag", test.getData().get(i).getName() + ""); } }}.start();
如下所示,我们已经成功的将 json 数据中所有的名字都解析出来了。
四、项目源码
项目源码下载地址。直接下载项目到本地然后导入就可以直接运行了,以上所有的 API 都是通过玩Android获取到的。
更多相关文章
- 20172323 2017-2018-2《程序设计与数据结构》第十一周学习总结
- Android多文件断点续传(二)——实现数据库储存下载信息
- Android数据存储方式:SharePreference、SQLite、ContentProvider
- android以后台service的方式获取GPRS数据
- Android 数据库对比
- 20、从头学Android之Android的数据存储--File