一.网络知识简介
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中
上面这个限制只有在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一号
文章首发地址 www.javayihao.top