OkHttp实现

OkHttp网络通信库无疑是当下最出色的网络框架之一,OkHttp是Square公司开发的,现在我们开始在AS中实现一下吧

ヾ(≧▽≦*)o

使用OkHttp

首先在使用OkHttp前,我们需要先在项目中添加OkHttp库的依赖包(无网络的情况下参考我的另一篇文章《向AS导入第三方本地-jar包和库》),在build.gradle的dependencies闭包里面添加如下内容

1
2
3
4
5
dependencies{
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
...
}
//根据OkHttp的版本号更改依赖包的版本号

小细节:在Android项目中请求网路一定要进行一下权限的注册,在AndroidMainfest中添加如下内容:

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

之后就可以正式开始我们的okhttp的实现啦

OkHttp具体用法如下:

首先创建OkHttpClient实例,这里我会将okHttpClient设置为全局变量,方便后续的使用

1
okHttpClient = new OkHttpClient();

如果要请求网络我们就需要创建一个Request对象:

1
Request request = new Request.Builder().build();

这里我们只创建了一个空的Request对象里面还没有内容,我们可以在build()的方法前连缀很多其他的方法来填充Request对象,比如:

1
Request request = new Request.Builder().url("https://getman.cn/echo").build();

url()方法是设置目标网络地址的,我们后续请求的网络就是这个网址的内容

之后我们调用OkHttpClient工具中的newCall()方法来创建一个Call对象,并将request参数放进去,写法如下:

1
Call call = okHttpClient.newCall(request);

然后用Response对象调用execute()方法来发送并获取服务器返回的数据:

1
Response response = call.execute();

这里execute会出现异常,我们需要使用try..catch来处理异常

到此OkHttp的简单用法就演示完了,但这只实用GET请求而POST请求我们需要创建一个表单也就是Form Body方法并在表单里面添加内容写法如下:

1
2
FormBody formBody = new FormBody.Builder()
.add("a", "1").add("b", "2").build();

同时request对象中需要加上.post()方法添加方法如下:

1
2
Request request = new Request.Builder().url("https://getman.cn/echo")
.post(formBody).build();

接下来就和GET方法一样了,是不是很简单啊(~ ̄▽ ̄)~,当然不会这么简单的,我们的GET请求和POST请求还有不同的请求方法分为同步请求和异步请求,下面解析一下同步请求和异步请求的区别

同步请求

web中的同步:

顺序处理,即使我们向服务器发出一个请求时,在服务器没返回结果给客户端之前,我们要一直处于等待状态直至服务器将结果返回到客户端,我们才能执行下一部操作。例如普通的B/S模式就是同步请求(注:B/S模式 也即服务器与浏览器通信主要采用HTTP协议;通信方式为“请求——响应”,浏览器发出请求;服务器做出响应。)

异步请求

web中的异步:

并行处理,当我们向服务器发出一个请求时,在服务器没返回结果之前,我们可以继续执行其他操作。例如AJAX技术就是异步请求。

例子

讲完类同步请求和异步请求和我们来实践一下两种请求不同的写法。

同步请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void postSync(View view){
new Thread(){

@Override
public void run() {
FormBody formBody = new FormBody.Builder()
.add("a", "1").add("b", "2").build();
Request request = new
Request.Builder().url("https://getman.cn/echo")
.post(formBody).build();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
Log.i("ljc", "getSync: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}

同步请求跟我们上面简单使用OkHttp方法大致相同,只是我们同步请求需要我们创建一个线程来使用,并且需用try..catch来处理异常

异步请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void postAsync(View view){

Request request = new Request.Builder().url("https://getman.cn/echo").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("ljc", "postAsync: " + response.body().string());
}
}
});
}

异步请求跟同步请求不一样的是,同步调用的是execute方法而异步则调用的是enqueue方法他需要我们传递一个Callback方法,Callback是一个接口其中有两个方法需要我们重写,一个是代表请求失败的方法另一个是代表请求结束的方法,在结束方法中我们通过

1
if (response.isSuccessful())

来判断是否请求成功,其中判断方法是当我们的相应码是200~299就算做成功

以上是同步请求和异步请求的写法。

POST数据提交

协议规定POST提交的数据必须放在请求体中,但协议并没有规定数据必须使用什么编码方式,而常用的数据编码方式有:

  • Content-Type: application/x-www-form-urlencoded

    数据被编码为名称/值对,默认类型;

  • Content-Type:multipart/form-data

    数据被编码为一条消息,一般用于文件上传;

  • Content-Type:application/octet-stream

    提交二进制数据,如果用于文件上传,只能上传一个文件;

  • Content-Type:application/json

    提交json数据

form-data

form-data编码方式的使用如下:

1
2
3
4
5
MultipartBody build = new MultipartBody.Builder()
.addFormDataPart("file1", file1.getName(),RequestBody.create (file1,MediaType.parse("text/plain")))
.addFormDataPart("file2", file2.getName(), RequestBody.create
(file1, MediaType.parse("text/plain")))
.build();

首先创建MultipartBody对象并调用addFormDataPart方法,然后创建几个要上传的文件,创建File对象将其参数放在addFormDataPart中。

1
2
File file1 = new File("C:\\Users\\ad\\Desktop\\1.txt");
File file2 = new File("C:\\Users\\ad\\Desktop\\2.txt");
json

json编码方式的使用如下:

1
RequestBody requestbody = new RequestBody.create("{\"a\":1,\"b\":2}",MediaType.parse("application/json")); 

相比于form-data,json编码不需要使用MultipartyBody。

OkHttp的配置

拦截器

拦截器的作用是可以在我们请求之前或者请求后进行操作,在请求前我们可以更改头部信息,在请求后我们可以回调请求数据

缓存与cookie

OkHttp按照Http协议规则实现了缓存的处理,缓存是比如:当我们发起第一次请求之后,如果后续还需进行同样的请求,此时如果符合缓存规则,则可以减少与服务器的通信,直接从本地缓存文件中读取响应返回给请求者。

1
2
3
OkHttpClient cache = new OkHttpClient.Builder().cache(
//存储文件夹的路径以及存储大小
new Cache(new File("/path/cache"),100)).build();

我们需要使用cache这个方法来实现OkHttp缓存

cookie是一些网站为了辨别用户身份,进行会话跟踪(比如确定登录状态)而存储在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
new OkHttpClient.Builder().cookieJar(new CookieJar() {
@Override
public void saveFromResponse(@NonNull HttpUrl httpUrl, @NonNull List<Cookie> list) {
cookies.put(httpUrl.host(),list); //在内存中存储

}

@NonNull
@Override
public List<Cookie> loadForRequest(@NonNull HttpUrl httpUrl) {
List<Cookie> cookies = MainActivity.this.cookies.get(httpUrl.host());
return cookies == null? new ArrayList<>():cookies; //空指针判断
}
}).build();

cookie我们需要调用cookieJar接口,他包含两个方法,第一个是服务器会把cookie封装成一个list集合回调给我们,我们需要将集合保存下来,第二个是把请求接口传递给我们让我们判断如果是这个网站的就返回这个网站的cookie,不是则不返回。以上代码中cookies是hashMap集合如下:

1
Map<String,List<Cookie>> cookies = new HashMap<>();

我们会将服务器分装的集合存储到这里面,后续在从这里调用。