zoukankan      html  css  js  c++  java
  • 《第一行代码》阅读笔记(二十八)——网络技术(OkHttp+JSON/GSON)

    网络技术在编程中也是非常重要的一环,在android底层是通过HttpURLConnection实现的,后来出现了一款优秀的框架OkHttp,实现了对底层的封装。然后随着技术的进步,现在更多的是使用OkHttp+Retrofit+Rxjava网络框架。这里书中没有详细说,后面笔者会对这些部分进行一个补充。

    WebView案例

    书中以一个内嵌的网页来打开网络技术的大门,让我们来一起看看吧。
    第一步:新建一个WebViewTest项目,修改activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <WebView
            android:id="@+id/web_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>
    

    第二步:修改MainActivity

    package com.firstcode.webviewtest;
    
    import android.os.Bundle;
    import android.webkit.WebView;
    import android.webkit.WebViewClient;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            WebView webView = findViewById(R.id.web_view);
            webView.getSettings().setJavaScriptEnabled(true);
            webView.setWebViewClient(new WebViewClient());
            webView.loadUrl("https://www.baidu.com/");
        }
    }
    

    非常的简单,就让我们来看下作者是怎么解释的吧

    ——第一行代码
    MainActivity中的代码也很短,首先使用findViewById( )方法获取到了WebView的实例,然后调用WebView的getSettings()方法可以去设置一些浏览器的属性,这里我们并不去设置过多的属性,只是调用了setJavaScriptEnabled ()方法来让WebView支持JavaScript 脚本。
    接下来是非常重要的一个部分,我们调用了WebView 的setWebViewClient()方法,并传人了一个WebViewClient的实例。这段代码的作用是,当需要从一个网页跳转到另一个网页时,我们希望目标网页仍然在当前WebView中显示,而不是打开系统浏览器。
    最后一步就非常简单了,调用WebView的loadUrl()方法,并将网址传入,即可展示相应网页的内容,这里就让我们看一看百度的首页长什么样吧。

    第三步:设置权限
    在AndroidManifest.xml中加入下面这句语句即可
    <uses-permission android:name="android.permission.INTERNET" />

    这个非常重要,经常容易忘记。

    HttpURLConnection

    通过WebView打开了网络世界的大门,之后我们就可以使用网络技术了。这就提到了一个HttpURLConnection,让我们看看是如何实现的吧。这个并不是很重要,因为后面要讲的OkHttp才是关键。但是底层的基础也不能完全不了解,所以大家还是需要看看。

    第一步:新建项目,修改主页布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
        <Button
            android:id="@+id/send_request"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Send Request" />
    
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <TextView
                android:id="@+id/response_text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </ScrollView>
    
    </LinearLayout>
    

    非常简单,不多说。

    第二步:修改主活动代码

    package com.firstcode.networktest;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    public class MainActivity extends AppCompatActivity {
    
        TextView responseText;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button sendRequest = (Button) findViewById(R.id.send_request);
            responseText = (TextView) findViewById(R.id.response_text);
    
            sendRequest.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    sendRequestWithHttpURLConnection();
                }
            });
        }
    
        private void sendRequestWithHttpURLConnection() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    HttpURLConnection connection = null;
                    BufferedReader reader = null;
                    try {
                        URL url = new URL("https://www.baidu.com/");
                        connection = (HttpURLConnection) url.openConnection();
                        connection.setRequestMethod("GET");
                        connection.setConnectTimeout(100000);
                        connection.setReadTimeout(100000);
                        InputStream in = connection.getInputStream();
    
                        reader = new BufferedReader(new InputStreamReader(in));
                        StringBuilder response = new StringBuilder();
                        String line;
                        while ((line = reader.readLine()) != null) {
                            response.append(line);
                        }
                        showResponse(response.toString());
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        if (reader != null) {
                            try {
                                reader.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        if (connection != null) {
                            connection.disconnect();
                        }
                    }
                }
            }).start();
        }
    
        private void showResponse(final String response) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    responseText.setText(response);
                }
            });
        }
    }
    
    

    笔者在这里做了一些修改,没有抽取点击事件了,怎么方便怎么来。其实大家也应该怎么做都会做,做到想放哪里就放哪里就OK了。

    这里主要说一下这个runOnUiThread() 方法,使用它是因为Android是不允许在子线程中进行UI操作的,我们需要通过这个方法将线程切换到主线程,然后再更新UI元素。

    注意事项

    如果是android版本比较高的手机用来做测试只能使用https的请求,http的请求无法显示,想让http的请求显示需要以下设置。

    1. 新建xml文件夹,并创建xml文件,如下图所示

    1. 输入以下内容
    <?xml version="1.0" encoding="utf-8"?>
    <network-security-config>
        <base-config cleartextTrafficPermitted="true" />
    </network-security-config>
    
    1. 最后在application标签中,加入android:networkSecurityConfig="@xml/config"

    post请求

    输入以下属性即可

    connection.setRequestMethod(" POST");
                        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
                        out.writeBytes("username=admin&password=123456");
    

    OkHttp的简单使用

    官网信息

    OkHttp官网
    Get a URL
    This program downloads a URL and prints its contents as a string. Full source.
    这段编码下载一个URL并将其内容打印为字符串。更多源码

    OkHttpClient client = new OkHttpClient();
    
    String run(String url) throws IOException {
      Request request = new Request.Builder()
          .url(url)
          .build();
    
      try (Response response = client.newCall(request).execute()) {
        return response.body().string();
      }
    }
    

    Post to a Server
    This program posts data to a service. Full source.
    这段编码提交一个data数据到服务器。更多源码

    public static final MediaType JSON
        = MediaType.get("application/json; charset=utf-8");
    
    OkHttpClient client = new OkHttpClient();
    
    String post(String url, String json) throws IOException {
      RequestBody body = RequestBody.create(json, JSON);
      Request request = new Request.Builder()
          .url(url)
          .post(body)
          .build();
      try (Response response = client.newCall(request).execute()) {
        return response.body().string();
      }
    }
    

    Further examples are on the OkHttp Recipes page.
    更多的例子在这里。

    看不懂?没关系,看看郭神怎么说。

    Get

    第一步:导入依赖
    implementation("com.squareup.okhttp3:okhttp:3.4.1")
    更新了一下导入依赖的方式,但是版本保持和作者的一样。

    第二步:修改sendRequestWithHttpURLConnection()为sendRequestWithOkHttp(),代码如下

    private void sendRequestWithOkHttp() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        OkHttpClient client = new OkHttpClient();
                        Request request = new Request.Builder()
                                .url("http://m.iyuba.cn/jlpt1/getConceptWordOver.jsp?app=primary")
                                .build();
                        Response response = client.newCall(request).execute();
                        String responseData = response.body().string();
                        showResponse(responseData);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    

    首先需要创建一个OkHttpClient实例。使用Request request = new Request.Builder().build();创建一个request的空对象,再通过链式编程.url()来获取接口。使用newCall回调一个call,再通过.execute()发送请求,并接收数据。最后通过response.body().string();获取内容。因为获取网络请求的线程是不能修改UI的所有需要编写一个方法来刷新UI,在这里就是showResponse(responseData);,它也是一个线程。

    Post

    post请求比get请求多一个RequestBody,具体如下:

    OkHttpClient client = new OkHttpClient();
                        RequestBody requestBody = new FormBody.Builder()
                                .add("username", "admin")
                                .add("password", "123456")
                                .build();                    
                        //需要可以接收RequestBody的url
                        Request request = new Request.Builder()
                                .url("***")
                                .post(requestBody)
                                .build();
                        Response response = client.newCall(request).execute();
                        String responseData = response.body().string();
    

    JSONObject

    现在网络上都使用JSON作为前后端交互的基础。如何使用JSON?
    第一步:添加方法parseJSONWithJSONObject,传入responseData

      parseJSONWithJSONObject(responseData);
                  showResponse(responseData);//
    

    第二步:编写方法

     private void parseJSONWithJSONObject(String jsonData) {
            try {
                JSONArray jsonArray = new JSONArray(jsonData);
                for (int i = 0; i < 5; i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    String voaId = jsonObject.getString("voa_id");
                    String word = jsonObject.getString("word");
                    Log.i(TAG, "id is" + voaId);
                    Log.i(TAG, "word id " + word);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    

    JSONArray可以实例化并接收json字符串,然后使用jsonArray.getJSONObject(i)获取每一个对象赋值给JSONObject,通过getString方法获取内容。非常好理解。

    Gson

    本章节没有使用书中那么简单的案例,正好实习公司有一段需求,拿来练练手,顺便记录下。

    第一步:导入依赖
    implementation 'com.google.code.gson:gson:2.8.6'

    第二步:安装插件
    书中也提到了需要为Gson数据匹配实体类,但是那太麻烦了。直接自动生成。插件名字是GsonFormat

    新建一个类,自动生成相应数据。步骤如下:

    没什么难度。

    第三步:修改

    因为笔者自己的链接,json数据有个嵌套,这个在公司中也是非常常见的。就像是数据库的一对多关系。有个size属性,和data属性,data中就是数据。如图

    如果使用书上的方法,会报错。
    Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 11 column 2 path $

    所以我们再建一个类,进行抽取。很巧妙吧

    package com.firstcode.okhttptest;
    
    import java.util.List;
    
    public class Temp {
        private String size;
        private List<Vocabulary> data;
    
        public String getSize() {
            return size;
        }
    
        public void setSize(String size) {
            this.size = size;
        }
    
        public List<Vocabulary> getData() {
            return data;
        }
    
        public void setData(List<Vocabulary> data) {
            this.data = data;
        }
    }
    

    其实只要把所有的json全部放到gsonformat的文本框里面就行,但是数据太多,电脑太烂,一运行就卡死。无奈提升了自己水平。

    第四步:修改parseJSONWithGson

    private void parseJSONWithGson(String jsonData) {
            Gson gson = new Gson();
            Temp temp = gson.fromJson(jsonData, Temp.class);
            List<Vocabulary> vocabularyList = temp.getData();
            for (Vocabulary v : vocabularyList) {
                Log.i(TAG, "word is" + v.getWord());
            }
        }
    

    结果

    书中还介绍了一种方法,值得注意。

    ——第一行代码
    如果需要解析的是一段JSON数组会稍微麻烦一点,我们需要借助TypeToken将期望解析成的数据类型传入到fromJson()方法中,如下所示:
    List people = gson.fromJson(jsonData, new TypeToken<List>() {}. getType());

    网络编程的最佳实例

    HttpURLConnection的就不写了,大家有兴趣的看下。

    OkHttp的主要实现方法就是

    package com.iyuba.primaryenglish.util;
    
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    
    public class HttpUtil {
    
        public static void sendOkHttpRequest(String address, okhttp3.Callback callback) {
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder().url(address).build();
            client.newCall(request).enqueue(callback);
        }
    }
    

    使用时,编写如下

    HttpUtil.sendOkHttpRequest("http://www.baidu.com", new okhttp3.Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    //在这里对异常情况进行处理
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    //得到服务器返回的具体信息
                    String reponseData = response.body().string();
                }
            });
    
  • 相关阅读:
    day91:luffy:基于vue+drf的路飞学城项目后端部署
    day90:luffy:基于vue+drf的路飞学城项目前端部署
    day89:luffy:使用Celery完成我的订单超时取消&Polyv视频加密播放
    day88:luffy:支付宝同步结果通知&接收异步支付结果&用户购买记录&我的订单
    day87:luffy:结算页面积分&支付宝接口
    day86:luffy:前端发送请求生成订单&结算页面优惠劵的实现
    day85:luffy:购物车根据有效期不同切换价格&购物车删除操作&价格结算&订单页面前戏
    C++中子类出现与父类同名成员函数如果调用父类函数
    C++继承方式引起子类中继承的父类属性访问权限的改变 && C++对象大小
    C++引用传递和指针传递区别
  • 原文地址:https://www.cnblogs.com/zllk/p/13416378.html
Copyright © 2011-2022 走看看