• 第一行代码Android 第九章9.4-9.5(解析JSON格式,网络编程最佳实践:发送HTTP请求的代码)


    9.4 解析JSON格式数据
            比起XML,JSON的主要优势在于它的体积更小,在网络上传输的时候可以更省流量。但是缺点在于语义性较差,看起来不如XML直观。

    在开始之前,需要在服务器的/htdocs目录中新建一个get_data.json的文件并编辑:

    1. //json格式
    2. [{"id":"5","version":"5.5","name":"Wang"},
    3. {"id":"3","version":"3.0","name":"Xiong"},
    4. {"id":"1","version":"3.1","name":"Wu"}]

    这时在浏览器中访问http://127.0.0.1/get_data.json网址就可以查看到上面的内容      

     9.4.1 使用JSONObject
            解析JSON数据也有很多种方法,这里介绍两种JSONObject和GSON。

    1. //修改MainActivity中的代码
    2. public class MainActivity extends AppCompatActivity implements Views.OnClickListener {
    3. ...
    4. private void sendRequestWithOkHttp() {
    5. new Thread(new Runnable() {
    6. @Override
    7. public void run() {
    8. try {
    9. OkHttpClient client = new OkHttpClient();
    10. //指定访问的服务器地址是电脑本机
    11. Request request = new Request.Builder().url("http://10.0.2.2/get_data.json").build();
    12. Response response = Client.newCall(request).execute();
    13. String responseData = response.body().string();
    14. //解析服务器返回的数据
    15. parseJSONWithJSONObject(responseData);
    16. } catch (Exception e) {
    17. e.printStackTrace();
    18. }
    19. }
    20. }).start();
    21. }
    22. ...
    23. private void parseJSONWithJSONObject(String jsonData) {
    24. try {
    25. //将服务器返回的数据传入一个JSONArray对象中
    26. JSONArray jsonArray = new JSONArray(jsonData);
    27. for (int i = 0; i < jsonArray.length(); i++) {
    28. JSONObject jsonObject = jsonArray.getJSONObject(i);
    29. String id = jsonObject.getString("id");
    30. String name = jsonObject.getString("name");
    31. String version = jsonObject.getString("version");
    32. Log.d("MainActivtiy","id is"+id);
    33. Log.d("MainActivity","name is"+name);
    34. Log.d("MainActivity","version is"+version);
    35. }
    36. } catch (Exception e) {
    37. e.printStackTrace();
    38. }
    39. }
    40. }

    9.4.2 使用GSON
            谷歌提供的GSON开源库可以让解析JSON数据的额工作简单到让你不敢想象的地步。
    注意:GSON并没有被添加到Android官方的API中,因此如果想要使用这个功能的话,就必须要在项目中添加GSON的依赖库。编辑app/build.gradle文件,在dependencies闭包中添加:
            compile 'com.google.code.gson:gson:2.7'

    GSON的用法

    1)例如JSON的字段有三个,我们可以定义一个类,并加入JSON的三个字段
        eg:Gson gson = new Gson();
            Person person = gson.fromJson(jsonData,Person.class);
    2)注意:如果解析的是一段JSON数组会稍微麻烦一点,我们需要借助TypeToken将期望解析成的数据类型传入到fromJson()方法中
        eg: List people = gson.fromJson(jsonData,newTypeToken>(){}.getType());

    1. //新增一个App类
    2. public class App {
    3. private String id;
    4. private String name;
    5. private String version;
    6. public String getId() {
    7. return id;
    8. }
    9. public String getName() {
    10. return name;
    11. }
    12. public String getVersion() {
    13. return version;
    14. }
    15. public void setId(String id) {
    16. this.id = id;
    17. }
    18. public void setName(String name) {
    19. this.name = name;
    20. }
    21. public void setVersion(String version) {
    22. this.version= version;
    23. }
    24. }

    1. //修改MainActivity中的代码
    2. public class MainActivity extends AppCompatActivity implements Views.OnClickListener {
    3. ...
    4. private void sendRequestWithOkHttp() {
    5. new Thread(new Runnable() {
    6. @Override
    7. public void run() {
    8. try {
    9. OkHttpClient client = new OkHttpClient();
    10. //指定访问的服务器地址是电脑本机
    11. Request request = new Request.Builder().url("http://10.0.2.2/get_data.json").build();
    12. Response response = Client.newCall(request).execute();
    13. String responseData = response.body().string();
    14. //解析服务器返回的数据
    15. parseJSONWithGSON(responseData);
    16. } catch (Exception e) {
    17. e.printStackTrace();
    18. }
    19. }
    20. }).start();
    21. }
    22. ...
    23. private void parseJSONWithGSON(String jsonData) {
    24. Gson gson = new Gson();
    25. List appList = gson.formJson(jsonData,new TypeToken>(){}.getType());
    26. for (App app : appList) {
    27. Log.d("MainActivtiy","id is"+app.getId());
    28. Log.d("MainActivity","name is"+app.getName());
    29. Log.d("MainActivity","version is"+app.getVersion());
    30. }
    31. }
    32. }

    9.5 网络编程的最佳实践
            由于一个应用程序很可能会在许多地方都用到网络功能,而发送HTTP请求的代码基本都是相同的,所以可以将这些通用的网络操作提取到一个公共的类里,并提供一个静态方法,当想要发起网络请求的时候,只需简单地调用一下这个方法即可。

    1. //创建一个类,并在类中新建一个静态方法
    2. public class HttpUtil {
    3. HttpURLConnection connection = null;
    4. try {
    5. URL url = new URL("http://www.baidu.com");
    6. connection = (HttpURLConnection) url.openConnetion(); //获取连接对象
    7. connection.setRequestMethod("GET"); //设置请求方式
    8. connection.setConnectTimeout(8000); //设置连接的超时时间
    9. connection.setReadTimeout(8000); //设置传递数据的超时时间
    10. connection.setDoInput(true);
    11. connection.setDoOutput(true);
    12. InputStream in = connection.getInputStream(); //获取服务器的响应流
    13. //下面对获取到的输入流进行读取
    14. BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    15. StringBuilder reponse = new StringBuilder();
    16. String line;
    17. while((line = reader.readLine()) != null) {
    18. response.append(line); //一行行的读取追加到StringBuilder中
    19. }
    20. return response.toString();
    21. } catch (Exception e) {
    22. e.printStackTrace();
    23. return e.getMessage();
    24. } finally {
    25. if (connection != null) {
    26. connection.disconnect(); // 关闭连接
    27. }
    28. }
    29. }
    30. }
    1. //每当需要发起一条HTTP请求的时候就可以这样写
    2. String address = "Http://www.baidu.com";
    3. String response = HttpUtil.sendHttpRequest(address);

    注意:由于sendHttpRequest()方法的内部并没有开启线程,这样就可能导致在调用sendHttpRequest()方法的时候内部并没有开启线程,这样就有可能导致在调用sendHttpRequest()方法的时候使得主线程被阻塞住。
    解决方法:使用Java的回调机制就可以解决。

    1. //首先需要定义一个接口,比如将它命名成HttpCallbackListener
    2. public interface HttpCallbackListener {
    3. void onFinish(String response); //服务器响应成功时调用,response是服务器返回的数据
    4. void onError(Exception e); //网络操作出现错误时调用
    5. }
    1. //继续修改HttpUtil中的代码
    2. public class HttpUtil {
    3. //给sendHttpRequest方法添加了一个HttpCallbackListener参数,并在内部开启了一个线程,在子线程里去执行具体的网络操作
    4. //子线程中是无法通过return语气来返回数据的,因此这里我们将服务器响应的数据传入了HttpCallbackListener的onFinish()方法中,,如果出现了异常就将异常原因传入到了onError()方法只能怪
    5. public static void sendHttpRequest(final String address, final HttpCallbackListener listener) {
    6. new Thread(new Runnbale() {
    7. @Override
    8. public void run() {
    9. HttpURLConnection connection = null;
    10. try {
    11. URL url = new URL("http://www.baidu.com");
    12. connection = (HttpURLConnection) url.openConnetion(); //获取连接对象
    13. connection.setRequestMethod("GET"); //设置请求方式
    14. connection.setConnectTimeout(8000); //设置连接的超时时间
    15. connection.setReadTimeout(8000); //设置传递数据的超时时间
    16. connection.setDoInput(true);
    17. connection.setDoOutput(true);
    18. InputStream in = connection.getInputStream(); //获取服务器的响应流
    19. //下面对获取到的输入流进行读取
    20. BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    21. StringBuilder reponse = new StringBuilder();
    22. String line;
    23. while((line = reader.readLine()) != null) {
    24. response.append(line); //一行行的读取追加到StringBuilder中
    25. }
    26. if (listener != null) {
    27. //回调onFinish()方法
    28. listener.onFinish(response.toString());
    29. } catch (Exception e) {
    30. if (listener != null) {
    31. //回调onError()方法
    32. listener.onError(e);
    33. }
    34. } finally {
    35. if (connection != null) {
    36. connection.disconnect(); // 关闭连接
    37. }
    38. }
    39. }
    40. }).start();
    41. }
    42. }
    1. //现在sendHttpRequest()方法接受两个参数了,因此我们在调用它的时候还需要将HttpCallbackListener的实例传入
    2. HttpUtil.sendHttpRequest(address,new HttpCallbackListener() {
    3. @Override
    4. public void onFinish(String response) {
    5. //在这里根据返回内容执行具体的逻辑
    6. }
    7. @Override
    8. public void onError(Exception e) {
    9. //在这里对异常情况进行处理
    10. }
    11. });
    1. //OKHttp写法会比较简单
    2. //在HttpUtil中加入一个sendOkHttpRequest()方法
    3. public class HttpUtil {
    4. ...
    5. public static void sendOkHttpRequest(String address,okhttp3.Callback callback) {
    6. okHttpClient client = new OkHttpClient();
    7. Request request = new Request.Builder().url(address).build();
    8. client.newCall(request).enqueue(callback); //enqueue方法内部已经帮我们开好线程了
    9. }
    10. }
    1. //那么我们在调用sendOkHttpRequest()方法的时候就可以这样写
    2. HttpUtil.sendOkHttpRequest("http://www.baidu.com",new okhttp3.Callback() {
    3. @Override
    4. public void onResponse(Call call,Response response) throws IOException {
    5. //得到服务器返回的具体内容
    6. String responseData = response.body().string();
    7. }
    8. @Override
    9. public void onFailure(Call call,IOException e) {
    10. //在这里对异常情况进行处理
    11. }
    12. });

    注意:不管是HttpURLConnection还是OkHttp,最终的回调接口都还是在子线程中运行的,因此我么不可以在这里执行任何的UI操作,除非借助runOnUIThread()方法来进行线程转换。
            

  • 相关阅读:
    在PowerBI中提取IFC文件中的数据
    【计算机专业毕设之基于ssm的大学生勤工俭学管理系统-哔哩哔哩】 https://b23.tv/IADQcmb
    UG NX11.0 软件安装教程
    小程序 词云图 echarts-for-weixin-wordcloud
    Spring Boot Security自带功能齐全的HttpFirewall防火墙
    Python调用Jumpserver的Api接口增删改查
    欧洲fba海运详解:欧洲fba海运怎么样?有哪些优势?
    C语言排序算法
    可视化容器管理工具-portainer.io使用
    前端时间分片渲染
  • 原文地址:https://blog.csdn.net/XXX_17/article/details/126147417