OkHttp入门学习|青训营笔记

150 阅读4分钟

这是我参与「第四届青训营」笔记创作活动的第1天。安卓基础班的课程还没有开始,在查看了大作业的要求后,决定先学习一下自己还不熟悉的技术,今天就决定从OkHttp开始学习。

准备工作

Gradle 依赖导入

implementation("com.squareup.okhttp3:okhttp:4.9.0")

清单文件权限设置

使用网络服务需要在清单文件中添加网络权限

<uses-permission android:name="android.permission.INTERNET"/>

OkHttp的同步与异步请求

发送get同步请求

OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url("https://www.httpbin.org/get?a=1&b=2").build();
//准备好请求的call对象
Call call = okHttpClient.newCall(request);
try {
    Response response = call.execute();
} catch (IOException e) {
    e.printStackTrace();
}

1.new OkHttpClient()构建一个OkHttpClient对象

2.使用Request.Builder()构建一个request对象

3.调用okHttpClientnewCall()方法传入刚才创建的request对象,创建一个准备好请求的call对象

4.执行call.execute()方法发送请求,同时获得返回的response

注意:在使用同步请求时,需要开辟一个子线程来执行操作,get请求的参数列表直接声明在了网址中。

发送get异步请求

Request request = new Request.Builder().url("https://www.httpbin.org/get?a=1&b=2").build();
Call call = okHttpClient.newCall(request);
//异步请求
call.enqueue(new Callback() {
    @Override
    public void onFailure(@NonNull Call call, @NonNull IOException e) {
        //请求失败回调
    }

    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
        //请求结束回调,并不意味着通信成功,只意味着与服务器通信成功
        if (response.isSuccessful()) {
            Log.i(TAG, "getAsync: " + response.body().string());
        }

    }
});

这里与get同步请求不同的是,异步请求调用的是call对象的enqueue()方法,而切异步请求是不需要开辟一个子线程的,因为enqueue()方法内会开辟子线程。

CallBack()中有两个重写的方法。在请求失败以后回调onFailure()方法。在请求结束后回调onResponse()方法,而onResponse()被调用也不意味着通信成功,只是与服务器通信成功(无论访问码是200、404或者其他)。

发送post同步请求

FormBody formBody = new FormBody.Builder().add("a", "1").add("a", "2").build();
//指明用post请求,否则自动使用get,post需要传递请求体
Request request = new Request.Builder().url("https://www.httpbin.org/post").post(formBody).build();
//准备好请求的call对象
Call call = okHttpClient.newCall(request);
try {
   Response response = call.execute();
   Log.i(TAG, "postSync: " + response.body().string());
} catch (IOException e) {
   e.printStackTrace();
}

发送post请求,需要在构建Request对象时指明使用post,否则会自动使用get,此时Request.Builder().post()post()中需要传入一个请求体作为参数,这里使用的FormBody类构建的formBody传入,其中添加了一系列参数。

注意:post请求的参数列表不在网址中。

发送post异步请求

//使用FormBody提交的方式构建请求体
FormBody formBody = new FormBody.Builder().add("a", "1").add("a", "2").build();
//指明用post请求,否则自动使用get,post需要传递请求体
Request request = new Request.Builder().url("https://www.httpbin.org/post").post(formBody).build();
//准备好请求的call对象
Call call = okHttpClient.newCall(request);

call.enqueue(new Callback() {
    @Override
    public void onFailure(@NonNull Call call, @NonNull IOException e) {
    }

    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {  
    }
});

post异步请求也是使用Call对象的enqueue()方法,同样的要构建请求体,其他部分同上。

post请求的数据提交方式

HTTP协议规定了post提交的数据必须放在请求体中,但并没有规定必须使用的编码方式,常用的数据编码方式可以在以下网址查看: www.runoob.com/http/http-c…

几个例子:

  • Content-Type:application/x-www-form-urlencoded : 数据编码为名/值对,默认类型
  • Content-Type:multipart/form-data : 数据编码为一条消息,一般用于文件上传
  • Content-Type:application/json : 用于提交json数据
File file = new File("/Users/lidayu/Downloads/te1.txt");
MultipartBody multipartBody = new MultipartBody.Builder()
        .addFormDataPart("file1", file.getName(), RequestBody.create(file, MediaType.parse("text/plain")))
        .build();
Request request = new Request.Builder().url("https://www.httpbin.org/post").post(multipartBody).build();

使用MultipartBody.Builder()构建请求体,addFormDataPart()传入要上传的文件信息,在RequestBody.create()方法的MediaType.parse()中声明数据编码方式。

OkHttp构建者的设置

OkHttp的自定义配置:

OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

okHttp可以在构建时设置拦截器,拦截器有以下两种

OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new xxx).build();
OkHttpClient okHttpClient = new OkHttpClient.Builder().addNetWorkInterceptor(new xxx).build();

加入拦截器后,执行请求时,请求过程中会执行一次拦截器的拦截方法,接到拦截器的响应之后,当前请求还没有发给服务器,可通过chain对象得到request对象,对其进行前置与后置处理:

OkHttpClient okHttpClient = new OkHttpClient.Builder().cache(new Cache(new File("/Users/lidayu/Downloads"),1024*1024)).addInterceptor(new Interceptor() {
    @NonNull
    @Override
    public Response intercept(@NonNull Chain chain) throws IOException {
        //前置处理
        Request request = chain.request()
                .newBuilder().addHeader("os", "android").addHeader("version", "1.0")
                .build();
        Response response = chain.proceed(request);
        //后置处理

        return response;
    }
}).addNetworkInterceptor(new Interceptor() {
    @NonNull
    @Override
    public Response intercept(@NonNull Chain chain) throws IOException {
        System.out.println(chain.request().header("version"));
        return chain.proceed(chain.request());
    }
}).build();

在执行前置处理后,请求才会发送给服务器。当多个请求需要添加上同样的数据内容时,使用拦截器会非常方便。

注意:在定义了多个同种拦截器时,先定义的先执行,当两种拦截器都被定定义时,addInterceptor(new xxx)addNetWorkInterceptor(new xxx)之前执行。

小结

1.发起get请求时,Call对象的execute()方法发起的是同步请求,需要在子线程中使用。enqueue()方法发起的是异步请求,不需要开辟子线程。

2.发起post请求时,需要在构建Request对象时指明使用post请求,并传入请求体,请求体有多种选择,根据需求使用即可,比如:FormBodyMultipartBody等。

3.可以灵活的使用拦截器减少重复工作。