如今基本上全部的网络框架都采用Okhttp、rxjava、retrofit三者一块儿写的。由于最近没有什么事情,就抽空总结一下这方面的知识:由于这些东西连在一期讲的话,不少同窗会以为懵逼,因此这里我准备先讲一下每个东西的用法,而后在讲解一下怎么联合使用。html
最近看了 《X特遣队/自杀小队》 以为不错。以一种混子的心态生活,其实挺轻松的!因此一张图片镇楼!习惯的我能够发给你!java
在这里先来个重要的说明:网络权限必定要加,必定要加!!!git
其实关于OkHttp的使用只要记住一个顺序就能够github
基本上记住上面的步骤就能够实现简单的请求了!chrome
既然上面都提到了相应的步骤,咱们就按照上面的步骤写一下就能够了!!!json
OkHttpClient httpClient = new OkHttpClient();
复制代码
建立一个对象而已,没有什么好说的!!!安全
Request request = new Request.Builder()
.method("GET", null)
.url("https://www.baidu.com/")
.build();
复制代码
这里简单说一下,method是设置相应的请求方式的;url是设置相应的请求地址的!其次Request是一个构建者的构建模式。剩下的没有什么好说的。,若是新手,不用管那么多为何,实现效果才是重要的!!!bash
Call call = httpClient.newCall(request);
复制代码
这里其实就是让httpClient知道本身要请求什么而已服务器
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(TAG, "请求失败的缘由:" + e);
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
Headers headers = response.headers();
Set<String> names = headers.names();
for (String name : names) {
Log.e(TAG, "请求的header" + name);
String value = headers.get(name);
Log.e(TAG, "值为: " + value + "\n----------------------------------");
}
final String date = response.body().string();
mHandler.post(new Runnable() {
@Override
public void run() {
mTvShow.setText(date);
}
});
}
});
复制代码
这里要说明的就多了:网络
当你的看到FATAL EXCEPTION: OkHttp Dispatcher这个异常的时候,恭喜你,你踩到第一个坑了!这个主要是由于response.body().string()
只能调用一次,若是你在代码中调用了两次,那么就会出现上面的异常;
当你异步请求的时候,是不能在子线程修改UI的,因此这里我用了一个Handler去操做相应的内容
若是你想看相应的一些内容的话,那么看那个for循环那里,你打印一下,就能看到以下的内容,若是不怎么理解的话,找大家后台人员请教一下!必定要虚心哦。
Accept-Ranges →bytes
Cache-Control →no-cache
Connection →Keep-Alive
Content-Length →227
Content-Type →text/html
Date →Wed, 05 Sep 2018 03:41:58 GMT
Etag →"5b7b7f40-e3"
Last-Modified →Tue, 21 Aug 2018 02:56:00 GMT
Pragma →no-cache
Server →BWS/1.1
Set-Cookie →BD_NOT_HTTPS=1; path=/; Max-Age=300
Strict-Transport-Security →max-age=0
X-Ua-Compatible →IE=Edge,chrome=1
复制代码
若是失败的话,那么就会在onFailure中把异常反馈给你!!!
给你贴下总体代码吧!
/*1.建立OkHttpClient对象*/
OkHttpClient httpClient = new OkHttpClient();
/*2.建立请求Request内容*/
Request request = new Request.Builder()
.method("GET", null)
.url("https://www.baidu.com/")
.build();
/*3.发送请求*/
Call call = httpClient.newCall(request);
/*4.建立请求的回调*/
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(TAG, "请求失败的缘由:" + e);
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
Headers headers = response.headers();
Set<String> names = headers.names();
for (String name : names) {
Log.e(TAG, "请求的header" + name);
String value = headers.get(name);
Log.e(TAG, "值为: " + value + "\n----------------------------------");
}
final String date = response.body().string();
mHandler.post(new Runnable() {
@Override
public void run() {
mTvShow.setText(date);
}
});
}
});
复制代码
以上步骤就能正常请求相应的数据了,若是尚未数据的话,好好看看代码!
关于POST请求的话,基本上就是比GET请求多一步设置表单的方法,也就是一个FormBody对象的设置,以key、value的方式设置表单而已,因此这里教你怎么写,而后我贴一下代码就那么滴了,谁让我那么懒呢!!!
表单的写法是这样的:
FormBody formBody = new FormBody.Builder()
.add("key", "value")
.build();
复制代码
其实add方法能够被调用屡次,添加相应的key和value;
总体的代码是这样的!!!
/*1.建立OkHttpClient对象*/
OkHttpClient httpClient = new OkHttpClient();
/*2.建立相应的表单内容*/
FormBody formBody = new FormBody.Builder()
.add("key", "value")
.build();
/*3.建立请求Request内容*/
Request request = new Request.Builder()
.url("https://www.baidu.com/")
.post(formBody)
.build();
/*4.发送请求*/
Call call = httpClient.newCall(request);
/*5.建立请求的回调*/
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(TAG, "请求失败的缘由:" + e);
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
Headers headers = response.headers();
Set<String> names = headers.names();
for (String name : names) {
Log.e(TAG, "请求的header" + name);
String value = headers.get(name);
Log.e(TAG, "值为: " + value + "\n----------------------------------");
}
final String date = response.body().string();
mHandler.post(new Runnable() {
@Override
public void run() {
mTvShow.setText(date);
}
});
}
});
}
复制代码
POST和GET请求只是请求的方式不一样,POST比较安全,全部内容都依靠表单传递!
在这里先来个重要的说明:去写SD卡的权限必定要加,必定要加!!!
说到文件上传,通常的网络请求都带有文件上传的功能,其实OkHttp3也能够上传文件,具体操做步骤以下:
由于其余的内容都差很少,只有关于表单的内容不通,因此这里着重讲一下关于这个表单的问题。
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("title", "张三")
.addFormDataPart("image", "zhangsan.jpg", RequestBody.create(MediaType.parse("application/octet-stream"), new File(Environment.getExternalStorageDirectory().getParent() + "/0/123.png")))
.build();
复制代码
通常这种上传文件,基本上都是传递相应的用户图片,修改图片什么的!由于服务器要根据你上传的这张图片进行相应图片的替换。回来讲上面那个配置:
总体代码是这样的:
/*1.建立OkHttpClient对象*/
OkHttpClient httpClient = new OkHttpClient();
/*2.建立相应的表单内容*/
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("title", "张三")
.addFormDataPart("image", "zhangsan.jpg", RequestBody.create(MediaType.parse("application/octet-stream"), new File(Environment.getExternalStorageDirectory().getParent() + "/0/123.png")))
.build();
/*3.建立请求Request内容*/
Request request = new Request.Builder()
.header("key", "value")
.url("https://www.baidu.com/")
.post(requestBody)
.build();
/*4.发送请求*/
Call call = httpClient.newCall(request);
/*5.建立请求的回调*/
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(TAG, "onFailure: " + e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.e(TAG, "onResponse: " + response.body().string());
}
});
复制代码
对了忘说了一点,图片是以流的形式进行传递的。因此上面"application/octet-stream"配置的是这种格式,若是是其余的格式呢?给你们一份对照表:参照一下就OK了。
参数 | 说明 |
---|---|
text/html | HTML格式 |
text/plain | 纯文本格式 |
text/xml | XML格式 |
image/gif | gif图片格式 |
image/jpeg | jpg图片格式 |
image/png | png图片格式 |
application/xhtml+xml | XHTML格式 |
application/xml | XML数据格式 |
application/atom+xml | Atom XML聚合格式 |
application/json | JSON数据格式 |
application/pdf | pdf格式 |
application/msword | Word文档格式 |
application/octet-stream | 二进制流数据 |
基本上你把上面的代码改吧改吧就能上传文件了!!!就酱紫简单。。。
配置请求时间和链接超时的时间等等
OkHttpClient httpClient = new OkHttpClient.Builder()
//设置相应的链接池
.connectionPool(new ConnectionPool())
//链接超时
.connectTimeout(15, TimeUnit.SECONDS)
//写入超时
.writeTimeout(15, TimeUnit.SECONDS)
//读取超时
.readTimeout(20, TimeUnit.SECONDS)
.build();
复制代码
每每在项目中,都会有一些关于公共请求参数的一些问题,这里就会用到相应的OkHttp拦截器!什么是拦截器呢?简单点说就和埋点差很少。在请求的时候,会走每个拦截器!想添加什么就添加什么,这里咱们经过几个实例讲解一下你就能大概理解了!
先看下代码,而后我在作一下相应的解释:
public class LogInterceptor implements Interceptor {
private static final String TAG = LogInterceptor.class.getSimpleName();
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
/*这样就能在请求以前打印相应的内容了*/
Log.e("url", String.format("Sending request %s on %s %n %s", request.url(), chain.connection(), request.headers()));
/*其实下面这个chain.proceed(request)这个方法,表明请求前和请求后*/
return chain.proceed(request);
}
}
复制代码
这里就是直接打印了一个相应的LOG,能够获取到一些请求的参数,这里说明一下:
request.url()
的值了,饮后后面的headers获取到的内容为空,由于GET请求没有相应的表单信息;chain.connection()
当你使用除了日志拦截器的时候,就会返回空chain.proceed(request)
表明请求响应的结果,因此说明你也是能够修改返回结果的!!!这个说来就有意思了,当你请求拦截器的时候,正常应该返回百度返回的内容,可是若是你修改了连接的地址会怎么样呢?固然就会返回你修改以后的返回地址了。。。咱们看看怎么实现的
public class ResetInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = new Request.Builder()
.method("GET", null)
.url("https://fanyi.baidu.com/translate?aldtype=16047&query=%E8%BF%9B%E5%BA%A6%0D%0A&keyfrom=baidu&smartresult=dict&lang=auto2zh#zh/en/%E9%87%8D%E7%BD%AE")
.build();
return chain.proceed(newRequest);
}
}
复制代码
对,你没有看错,就这么赤裸裸的换了一个url地址,其实Request request = chain.request();
这个方法,返回的Request就是在建立的时候,建立的Request,因此,这里你直接,经过拦截器,直接建立一个新的,直接返回就能够了,就没有以前的Request什么事情了!!!其实就至关于你把以前的内容从新写了一遍!就酱紫了。。。
其实这个的实现和上面的差很少,也就是替换相应的Request的内容!可是这里你要考虑一个问题,就是GET请求和POST请求的处理方式应该是不一样的,多以这里要分状况去处理。不然不能达到你想要的效果的!因此这里咱们分开说。先说明一下,GET请求是在Url后面拼接相应的参数,而POST请求是在form表单中添加相应的参数,因此方式必定是不同的!!!
先来一段代码体验一下:
HttpUrl build = originalRequest.url().newBuilder()
.addQueryParameter("key1", "value1")
.addQueryParameter("key2", "value2")
.addQueryParameter("key3", "value3")
.addQueryParameter("key4", "value4")
.addQueryParameter("key5", "value5")
.build();
Request request = originalRequest.newBuilder().url(build).build();
复制代码
这样就能够添加相应的公共请求参数了,其实开始的时候,我觉得newBuilder()是建立一个新的内容呢?其实它是拿到以前的内容,而后把下面的内容添加进去。因此这里其余的内容是不会收到影响的!!!
其实GET请求就是在URL后面追加上相应的参数。
仍是先来一点代码体验一下:
Request requestBuilder = originalRequest.newBuilder()
.addHeader("key1", "value1")
.addHeader("key2", "value2")
.addHeader("key3", "value3")
.addHeader("key4", "value4")
.addHeader("key5", "value5")
.build();
复制代码
和上面的相似,只是写法不一样而已!由于POST请求添加的是相应的header。
总体的代码以下:
public class PublicInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if ("GET".equals(request.method())) {
//GET请求的处理
HttpUrl build = request.url().newBuilder()
.addQueryParameter("key1", "value1")
.addQueryParameter("key2", "value2")
.addQueryParameter("key3", "value3")
.addQueryParameter("key4", "value4")
.addQueryParameter("key5", "value5")
.build();
request = request.newBuilder().url(build).build();
} else if ("POST".equals(request.method())) {
request = request.newBuilder()
.addHeader("key1", "value1")
.addHeader("key2", "value2")
.addHeader("key3", "value3")
.addHeader("key4", "value4")
.addHeader("key5", "value5")
.build();
}
return chain.proceed(request);
}
}
复制代码
最后在把相应的Interceptor添加到OkHttp就行了。
2018年10月15日补充:
在POST请求中,请求参数应该添加到body中,因此上面代码是有问题的!
替换成下面这样:
if (originalRequest.body() instanceof FormBody) {
// 构造新的请求表单
FormBody.Builder builder = new FormBody.Builder();
FormBody body = (FormBody) originalRequest.body();
//将之前的参数添加
for (int i = 0; i < body.size(); i++) {
builder.add(body.encodedName(i), body.encodedValue(i));
}
//追加新的参数
builder.add("key1", "value1");
builder.add("key2", "value2");
builder.add("key3", "value3");
builder.add("key4", "value4");
builder.add("key5", "value5");
//构造新的请求体
originalRequest = originalRequest.newBuilder().post(builder.build()).build();
}
复制代码
对于以上的错误深表歉意,由于没有弄清楚http中的一下内容,还请见谅!!!
基本上使用的时候就这么多问题,可能有些讲解不到的,若是有什么不到位的,及时补充!!!有问题留言,我看到了必定会回复你的!!!