一.网络知识简介

       1. 网络操作是Android开发中很重要的一部分,我们在移动端开发的app如何不断地向服务器发送请求并接受服务器发送来的json格式的字符串,通过json解析技术把指定的内容展示在指定的控件上面。

       2. 首先客户端在发送请求之前是需要TCP或者UDP来基于三次握手技术和服务端建立连接,然后通过http协议这种应用技术发送请求和接收响应,http提供了封装或者显示数据的具体形式,Socket提供了网络通信的能力。

       3. 网络请求方式:GET和POST

GET 主要作用是从服务器获取数据,方式是将参数拼接在url后面,前端直接可以看到,传输层角度来说不是很安全,但是本质层来说,因为get是获取数据不会对服务器数据修改,所以安全。

POST主要作用是给服务器提交数据,方式是将数据放在数据包发送,看不到的,传输层角度来说比较安全,但是本质层来说,因为post是操作是对服务器数据修改,所以不是很安全。

二:get请求数据(原生方法)

public class IndexActivity extends AppCompatActivity implements View.OnClickListener {
private String result;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
URL url = null;
try {
//获取URL实例
url = new URL("xxxx请求地址");
//获取链接对象
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//设置请求方法
connection.setRequestMethod("GET");
//设置请求超时时间
connection.setConnectTimeout(30 * 1000);
connection.setRequestProperty("Content-type", "application/json");
connection.setRequestProperty("Charset", "UTF-8");
connection.setRequestProperty("Accept-Charset", "UTF-8");
//发起连接
connection.connect();
int responseCode = connection.getResponseCode();
String message = connection.getResponseMessage();
if (responseCode == HttpURLConnection.HTTP_OK) {
//获取inputStream流
InputStream inputStream = connection.getInputStream();
//将得到的inputStream流转成字符串
result = streamToString(inputStream);
Log.e("结果是", result);
final TextView textView = findViewById(R.id.result);
runOnUiThread(new Runnable() {
@Override
public void run() {
result=decode(result);
textView.setText(result);
}
});
/* textView.post(new Runnable() {
@Override
public void run() {
textView.setText(result);
}
});*/
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();

}

/**
* inputStream转为String
*
* @param in 要传入的流对象
* @return 结果字符串
*/
private String streamToString(InputStream in) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();//定义一个输出管道
byte[] buffer = new byte[1024];
int len;
while ((len = in.read()) != -1) {//写入管道
baos.write(buffer, 0, len);
}
baos.close();
in.close();
byte[] bytesArray = baos.toByteArray();//管道转为字节数组
return new String(bytesArray);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

/**
* 将Unicode字符转换为UTF-8类型字符串
*/
public static String decode(String unicodeStr) {
if (unicodeStr == null) {
return null;
}
StringBuilder retBuf = new StringBuilder();
int maxLoop = unicodeStr.length();
for (int i = 0; i < maxLoop; i++) {
if (unicodeStr.charAt(i) == '\\') {
if ((i < maxLoop - 5)
&& ((unicodeStr.charAt(i + 1) == 'u') || (unicodeStr
.charAt(i + 1) == 'U')))
try {
retBuf.append((char) Integer.parseInt(unicodeStr.substring(i + 2, i + 6), 16));
i += 5;
} catch (NumberFormatException localNumberFormatException) {
retBuf.append(unicodeStr.charAt(i));
}
else {
retBuf.append(unicodeStr.charAt(i));
}
} else {
retBuf.append(unicodeStr.charAt(i));
}
}
return retBuf.toString();
}
}

重点:

1.因为我们请求网络数据会有数据等待,这时候如果我们在主线程中操作,就会出现卡死主线程异常,所以对于数据请求的操作我们要放在一个子线程中让其运行

2.在涉及到请求网络的时候在mainifest配置文件中需要声明网络权限

<uses-permission android:name="android.permission.ACCEPT_HANDOVER"/>

3.只有在主线程中才能更新ui,子线程中不能操作ui,可以通过Handler更新UI,后面或介绍这种方法,这里还有两种处理方法就是

代码中的

runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(result);
}
});

把ui更新操作放到主线程中运行

另外就是TextView的post方法可以直接将操作更新到主线程中进行

textView.post(new Runnable() {
@Override
public void run() {
textView.setText(result);
}
});

4.在Android9.0中对http的请求进行了限制,不能访问,我们需要在res中创建一个xml/network-security-config文件

增加cleartextTrafficPermitted属性,如下

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted = "true"/>
</network-security-config>

添加到安全配置文件mainifest.xml中

Android网络部分-----网络数据请求、解析_ico

上面这个限制只有在9.0中并且

targetSdkVersion 是29才会发生

三:post请求

public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
URL url = null;
try {
//获取URL实例
url = new URL("xxxx请求地址,不带有参数");
//获取链接对象
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//设置请求方法
connection.setRequestMethod("POST");
//设置请求超时时间
connection.setConnectTimeout(30 * 1000);
connection.setRequestProperty("Content-type", "application/json");
connection.setRequestProperty("Charset", "UTF-8");
connection.setRequestProperty("Accept-Charset", "UTF-8");
connection.setDoOutput(true);
connection.setDoInput(true);
//不用缓存
connection.setUseCaches(false);
//发起连接
connection.connect();
String data = "username=" + URLEncoder.encode("123", "UTF-8") + "123";/*有编码问题的的也可以处理*/
OutputStream outputStream = connection.getOutputStream();
outputStream.write(data.getBytes());
outputStream.flush();
outputStream.close();
int responseCode = connection.getResponseCode();
String message = connection.getResponseMessage();
if (responseCode == HttpURLConnection.HTTP_OK) {
//获取inputStream流
InputStream inputStream = connection.getInputStream();
//将得到的inputStream流转成字符串
result = streamToString(inputStream);
Log.e("结果是", result);
final TextView textView = findViewById(R.id.result);
runOnUiThread(new Runnable() {
@Override
public void run() {
result = decode(result);
textView.setText(result);
}
});
/* textView.post(new Runnable() {
@Override
public void run() {
textView.setText(result);
}
});*/
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}

上面的get和post都是通过原生实现的,实际生产场景中往往使用第三方库

四:数据解析

我们通过上面的get或者post方法从网络拿到数据之后,如何把得到的json字符串解析呢?

解析json数据主要两种方法,第一种使用JSONObject解析json数据,第二种使用第三方库解析,比如谷歌提供的GSON解析JSON数据,这里演示JSONObject解析json数据

用于测试的json数据如下

{
"status": 1,
"data": [{
"id": 1,
"name": "abc"
},
{
"id": 2,
"name": "123"
}
],
"msg": "成功"
}

在json数据中每一个{}代表一个JSONObject即json对象,每一个[ ]就是一个JSONArray即json数组,所以案例数据就是一个json对象包含了一个json数组,这个json数组里面有两个json对象

我们定义对应的实体类(set、get方法省)

//最外面的json对象
public class Result {
private int status;
//json数组
private List<Person> personList;
//json数组里面的对象
private static class Person{
private int id;
private String name;
}
}

解析java代码

 public void jsonToPo(String resultJson) throws JSONException {
JSONObject resultObject = new JSONObject(resultJson);
int status = resultObject.getInt("status");
JSONArray jsonArray = resultObject.getJSONArray("data");
Result result = new Result();
List<Result.Person> personList = new ArrayList<>();
result.setStatus(status);
if (jsonArray != null && jsonArray.length() > 0) {
for (int i = 0; i < jsonArray.length(); i++) {
//遍历每一个json对象
JSONObject jsonObject = (JSONObject) jsonArray.get(i);
int id = jsonObject.getInt("id");
String name = jsonObject.getString("name");
Result.Person person = new Result.Person();
person.setId(id);
person.setName(name);
//添加到list中
personList.add(person);
}
result.setPersonList(personList);
}
}

更多内容关注微信公众号 java一号