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();
                }
            });
    
  • 相关阅读:
    leetcode 29-> Divide Two Integers without using multiplication, division and mod operator
    ros topic 发布一次可能会接收不到数据
    python中的print()、str()和repr()的区别
    python 部分函数
    uiautomatorviewer错误 unable toconnect to adb
    pyqt 不规则形状窗口显示
    appium 计算器demo
    Spring 3.0 注解注入详解
    Spring Autowire自动装配
    restful 学习地址
  • 原文地址:https://www.cnblogs.com/zllk/p/13416378.html
Copyright © 2011-2022 走看看