okhttp协议的学习(详细,方方面面)

Posted 春招进大厂的梦想家

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了okhttp协议的学习(详细,方方面面)相关的知识,希望对你有一定的参考价值。

okhttp协议的学习

1.导入依赖:

implementation 'com.squareup.okhttp3:okhttp:4.2.2'

2.使用OKhttp发起get请求

1.创建一个活动,在其xml文件内编写:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activity.OkHttpActivity"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="getrequest"
        android:textAllCaps="false"
        android:onClick="GetRequest"
        tools:ignore="OnClick" />
</LinearLayout>

2.在.java文件内编写

public class OkHttpActivity extends AppCompatActivity {

    public final static String TAG = "OkHttpActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ok_http);
    }

    public void GetRequest(View view) {
        //首先要有一个客户端,类似于要有一个浏览器
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                //在此处设置时间,和Http协议中的一样
                .connectTimeout(100000, TimeUnit.MILLISECONDS)
                //记得一定要build
                .build();
        //创建请求内容
        final Request request = new Request.Builder()
                //设置请求方式
                .get()
                //设置URL
                .url("https://wanandroid.com/wxarticle/chapters/json")
                //这里也要build
                .build();
        //用client去创建请求内容
        Call task = okHttpClient.newCall(request);
        //进行异步请求
        task.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                Log.d(TAG, "onFailure: " + e.toString());
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                //这里获取返回的状态码。和HTTP协议是一样的,对比参考
                int code = response.code();
                if ((code == HttpURLConnection.HTTP_OK)) {
                    //这里的body就是请求到的内容了,是response.body
                    ResponseBody body = response.body();
                    //body是个对象,用body.string把它变成字符串,这里也要记得哦
                    Log.d(TAG, "onResponse: " + body.string());
                }
            }
        });
    }

代码的解释已经在注释中写的很详尽了,可以与HTTP协议做作对比。多用!多用!!熟能生巧!!!

3.在UI中显示从服务器返回的数据

1.创建一个活动,在其xml文件中编写:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activity.OkHttpActivity"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="getrequest"
        android:textAllCaps="false"
        tools:ignore="OnClick" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/text_okhttp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </ScrollView>
</LinearLayout>

具体什么用呢?就是想要实现一个点击按钮,然后下方出现从服务器获取到的数据。

2. 在.java文件

public class OkHttpActivity extends AppCompatActivity implements View.OnClickListener {

    public final static String TAG = "OkHttpActivity";
    private GetTextItem getTextItem;
    private TextView tv_http;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ok_http);
        tv_http = findViewById(R.id.text_okhttp);
        Button btu = findViewById(R.id.btn);
        btu.setOnClickListener(this);
    }
    private void GetRequest() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 创建一个OkHttpClient的实例
                    OkHttpClient client = new OkHttpClient();
                    // 如果要发送一条HTTP请求,就需要创建一个Request对象
                    // 可在最终的build()方法之前连缀很多其他方法来丰富这个Request对象
                    Request request = new Request.Builder()
                            .url("https://wanandroid.com/wxarticle/chapters/json")
                            .build();
                    // 调用OkHttpClient的newCall()方法来创建一个Call对象,并调用execute()方法来发送请求并获取服务器的返回数据
                    Response response = client.newCall(request).execute();
                    // 其中Response对象就是服务器返回的数据,将数据转换成字符串
                    String responseData = response.body().string();
                    // 将获取到的字符串传入showResponse()方法中进行UI显示
                    updateUI(responseData);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void updateUI(final String responsese) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //这里进行UI操作
                tv_http.setText(responsese);
            }
        });
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn:
                GetRequest();
                break;
            default:
                break;
        }
    }
}

这就是全部的流程了,但是特别要注意:不能用xml文件内的onClick,必须中规中矩的设置id,找到控件,设置点击事件这些流程。

然后就是多用一哈,就问题不大了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pP681aD8-1620478687702)(C:\\Users\\23737\\AppData\\Roaming\\Typora\\typora-user-images\\image-20210508101747168.png)]

4.同步和异步传输的区别:

**同步:**发送请求到服务器之后,等数据返回的过程中不能向下执行,只能等数据返回后才能继续执行代码;

异步: 异步传输和同步传输相反,异步传输指的是等数据返回的过程中可以继续执行;一般都在用异步传输。

5.post方式提交字符串

1.继续新建活动,在xml文件下添加一个按钮,用来提交字符串

2.继续创建一个实体类,用来将json封装成一个类

public class CommentItem {
    private String username;
    private String password;
    private String repassword;

    public String getRepassword() {
        return repassword;
    }

    public CommentItem(String username) {
        this.username = username;
    }


    public CommentItem(String username, String password,String repassword) {
        this.username = username;
        this.password = password;
        this.repassword = repassword;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

3.最后在.java文件下编写代码(与get方式有区别,注意区分):

public class OkHttpPostActitivty extends AppCompatActivity {
    public final static String TAG = "OkHttpPostActitivty";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ok_http_post_actitivty);
    }

    public void PostRequest(View view){
        //要有一个浏览器client
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(100000, TimeUnit.MILLISECONDS)
                .build();
        
        //post里面要提交内容,所以在这儿要设置内容
        CommentItem commentItem = new CommentItem("123456","hsk","hsk");
        Gson gson = new Gson();
        String jsonStr = gson.toJson(commentItem);
           //MediaType媒体类型:决定浏览器将以什么形式、什么编码对资源进行解析
        MediaType mediaType = MediaType.parse("application/json");
        final RequestBody requestBody = RequestBody.create(jsonStr,mediaType);
        
        //创建请求内容
        Request request   = new Request.Builder()
                .post(requestBody)
                .url("https://www.wanandroid.com/user/register")
                .build();

        //client去创建请求任务
        Call task = okHttpClient.newCall(request);
        task.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                Log.d(TAG, "onFailure: "+e.toString());
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                int code = response.code();
                ResponseBody body = response.body();
                if (body != null) {
                    Log.d(TAG, "onResponse: "+body.string());
                }
            }
        });
    }
}

首先需要注意的是既然是post方式提交,必须要有提交内容。所以在设置请求内容之前就必须先设置内容。Gson解析,然后RequestBody把内容封装起来,最后传入post内的参数里面。

在异步传输的过程中也要注意,onResponse()里面也要用RequestBody来获取内容。通俗的说RequestBody在网络编程这块很多都是用来获取内容。

4.MediaType

类型描述
text/htmlHTML格式
text/plain纯文本格式,空格转换为 “+” 加号,但不对特殊字符编码
text/xmlXML格式
text/x-markdownMarkdown格式
image/gifgif图片格式
image/jpegjpg图片格式
image/pngpng图片格式
application/xhtml+xmlXHTML格式
application/xmlXML数据格式
application/json用来告诉服务端,消息主体是序列化后的JSON字符串
application/pdfpdf格式
application/mswordWord文档格式
application/octet-stream二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded参数为键值对形式,在发送前编码所有字符(默认)。浏览器的原生 <form encType=”” 表单提交类型,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据
multipart/form-data不对字符编码,发送大量二进制数据或包含non-ASCII字符的文本,application/x-www-form-urlencoded是效率低下的(需要用更多字符表示一个non-ASCII字符)。需要设定“ <form enctype=‘multipart/form-data’

6.使用OKhttp上传单个文件

1.继续创一个新活动,添加一个按钮,添加点击事件

2. 实现的代码部分

public class OkHttpPostFileActitivty extends AppCompatActivity {
    public static final String BASE_URL = "http://10.0.2.2:9102";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ok_http_post_file_actitivty);
    }

    public void OhPostFile(View view){
        //首先要有一个浏览器client
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(100000, TimeUnit.MILLISECONDS)
                .build();

        //因为addFormDataPart()中需要传入一个文件名,所以要在这创建文件
        File file = new File("/storage/emulated/Android/data/files/1.png");

        //因为RequestBody.create需要传入一个MediaType,所以在此创建
        MediaType mediaType = MediaType.parse("/image/png");

        //因为addFormDataPart()中还需要传入一个requestBody,所以要在这创建
            //RequestBody.create()中需要传参的原因:里面存放一些信息参数。例如用的什么编码。如果客户端与服务器端编码不一致,那下载下来可能就有乱码了。这相当于是一个事先说明
        RequestBody fileBidy = RequestBody.create(file,mediaType);

        //post要传进去一个RequestBody,所以在这设置内容
        RequestBody requestBody = new MultipartBody.Builder()
                .addFormDataPart("file",file.getName(),fileBidy)
                .build();

        //创建一个请求内容
        Request request = new Request.Builder()
                .post(requestBody)
                .url(BASE_URL + "/file/upload")
                .build();

        //client创建请求任务
        Call task = okHttpClient.newCall(request);

        //异步请求
        task.enqueue(new Callback() {
            private static final String TAG = "OkHttpPostFileActitivty";

            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                Log.d(TAG, "onFailure: "+e.toString());
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                int code = response.code();
                if(code == 200){
                    ResponseBody body = response.body();
                    if (body != null) {
                        String string = body.string();
                        Log.d(TAG, "onResponse: "+string);
                    }
                }
            }
        });
    }
}

补充一点重要的东西:

  • RequestBody.create()携带的参数有什么用呢?答:里面存放一些信息参数,例如用的什么编码。如果客户端与服务器端编码不一致,那下载下来可能就有乱码了。这相当于是一个事先说明;
  • RequestBody是干嘛呢? 答:RequestBody的作用其实是将json格式的字符串转换为java对象;
  • https://blog.csdn.net/yihuangol/article/details/105434590?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5.vipsorttest&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5.vipsorttest

7.使用OKhttp上传多个文件

1.添加一个按钮并且为其添加点击事件

2.编辑代码(和上传单文件基本相同)

public void OhPostFiles(View view){
        //首先要有一个浏览器client
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(100000, TimeUnit.MILLISECONDS)
                .build();

        //因为addFormDataPart()中需要传入一个文件名,所以要在这创建文件
        File fileOne = new File("/storage/emulated/Android/data/files/1.png");
        File fileTwo = new File("/storage/emulated/Android/data/files/2.png");
        File fileThree = new File("/storage/emulated/Android/data/files/3.png");
        File fileFour = new File("/storage/emulated/Android/data/files/4.png");

        //因为RequestBody.create需要传入一个MediaType,所以在此创建
        MediaType mediaType = MediaType.parse("/image/png");

        //因为addFormDataPart()中还需要传入一个requestBody,所以要在这创建

以上是关于okhttp协议的学习(详细,方方面面)的主要内容,如果未能解决你的问题,请参考以下文章

Okhttp3 设计思想学习

Okhttp3 设计思想学习

TCP协议要点和难点全解

TCP协议疑难杂症全景解析

OkHttp学习 - POM 文件

OkHttp学习 - POM 文件