ip okhttp 设置_#Android#OkHttp3使用指南

知识框架(脑图)

Okhttp3脑图

出现背景

网络访问的高效性要求,可以说是为高效而生

解决思路

提供了对 HTTP/2 和 SPDY 的支持,这使得对同一个主机发出的所有请求都可以共享相同的套接字连接

如果 HTTP/2 和 SPDY 不可用,OkHttp 会使用连接池来复用连接以提高效率

提供了对 GZIP 的默认支持来降低传输内容的大小

提供了对** HTTP 响应的缓存机制**,可以避免不必要的网络请求

当网络出现问题时,OkHttp 会自动重试一个主机的多个 IP 地址

OkHttp3设计思路

具体步骤

(1)添加网络访问权限并添加库依赖

compile 'com.squareup.okhttp3:okhttp:3.4.1'

(2)GET

OkHttpClient client = new OkHttpClient();

String run(String url) throws IOException {

Request request = new Request.Builder()

.url(url)

.build();

Response response = client.newCall(request).execute();

return response.body().string();

}

(3)POST

public static final MediaType JSON

= MediaType.parse("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();

Response response = client.newCall(request).execute();

return response.body().string();

}

(3)异步调用

使用enqueue方法,将call放入请求队列,然后okHttp会在线程池中进行网络访问;只需要在适当的时候(需要操作UI的时候)发送一个消息给主线程的Handler(取决于Looper,使用Looper.getMainLooper()创建的Handler就是主线程Handler)就可以了~

private Handler mHandler;

private TextView mTxt;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_home);

mTxt = (TextView) findViewById(R.id.txt);

mHandler = new Handler(Looper.getMainLooper()){

@Override

public void handleMessage(Message msg) {

mTxt.setText((String) msg.obj);

}

};

OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder().url("https://github.com").build();

client.newCall(request).enqueue(new Callback() {

@Override

public void onFailure(Call call, IOException e) {

}

@Override

public void onResponse(Call call, Response response) throws IOException {

Message msg = new Message();

msg.what=0;

msg.obj = response.body().string();

mHandler.sendMessage(msg);

}

});

}

(4)HTTP头部的设置和读取

HTTP 头的数据结构是 Map>类型。也就是说,对于每个 HTTP 头,可能有多个值。但是大部分 HTTP 头都只有一个值,只有少部分 HTTP 头允许多个值。OkHttp的处理方式是:

使用header(name,value)来设置HTTP头的唯一值

使用addHeader(name,value)来补充新值

使用header(name)读取唯一值或多个值的最后一个值

使用headers(name)获取所有值

OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()

.url("https://github.com")

.header("User-Agent", "My super agent")

.addHeader("Accept", "text/html")

.build();

Response response = client.newCall(request).execute();

if (!response.isSuccessful()) {

throw new IOException("服务器端错误: " + response);

}

System.out.println(response.header("Server"));

System.out.println(response.headers("Set-Cookie"));

(5)表单提交

RequestBody formBody = new FormEncodingBuilder()

.add("query", "Hello")

.build();

(6)文件上传

使用MultipartBuilder指定MultipartBuilder.FORM类型并通过addPart方法添加不同的Part(每个Part由Header和RequestBody两部分组成),最后调用builde()方法构建一个RequestBody。

MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");

RequestBody requestBody = new MultipartBuilder()

.type(MultipartBuilder.FORM)

.addPart(

Headers.of("Content-Disposition", "form-data; name=\"title\""),

RequestBody.create(null, "测试文档"))

.addPart(

Headers.of("Content-Disposition", "form-data; name=\"file\""),

RequestBody.create(MEDIA_TYPE_TEXT, new File("input.txt")))

.build();

(7)使用流的方式发送POST请求

OkHttpClient client = new OkHttpClient();

final MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");

final String postBody = "Hello World";

RequestBody requestBody = new RequestBody() {

@Override

public MediaType contentType() {

return MEDIA_TYPE_TEXT;

}

@Override

public void writeTo(BufferedSink sink) throws IOException {

sink.writeUtf8(postBody);

}

@Override

public long contentLength() throws IOException {

return postBody.length();

}

};

Request request = new Request.Builder()

.url("http://www.baidu.com")

.post(requestBody)

.build();

Response response = client.newCall(request).execute();

if (!response.isSuccessful()) {

throw new IOException("服务器端错误: " + response);

}

System.out.println(response.body().string());

(8)缓存控制

强制不缓存,关键:noCache()

Request request = new Request.Builder()

.cacheControl(new CacheControl.Builder().noCache().build())

.url("http://publicobject.com/helloworld.txt")

.build();

缓存策略由服务器指定,关键:maxAge(0, TimeUnit.SECONDS)

Request request = new Request.Builder()

.cacheControl(new CacheControl.Builder()

.maxAge(0, TimeUnit.SECONDS)

.build())

.url("http://publicobject.com/helloworld.txt")

.build();

强制缓存,关键:onlyIfCached()

Request request = new Request.Builder()

.cacheControl(new CacheControl.Builder()

.onlyIfCached()

.build())

.url("http://publicobject.com/helloworld.txt")

.build();

Response forceCacheResponse = client.newCall(request).execute();

if (forceCacheResponse.code() != 504) {

// The resource was cached! Show it.

} else {

// The resource was not cached.

}

允许使用旧的缓存,关键:maxStale(365, TimeUnit.DAYS)

Request request = new Request.Builder()

.cacheControl(new CacheControl.Builder()

.maxStale(365, TimeUnit.DAYS)

.build())

.url("http://publicobject.com/helloworld.txt")

.build();

Q&A

问题1:CalledFromWrongThreadException怎么破?

分析:从错误的线程调用,是因为在主线程中操作UI,这在Android中是不允许的,所以需要切换到主线程中进行UI操作。

解决:参见 (6)异步调用

问题2:Cookies没有被缓存怎么破?

分析:Cookies由CookieJar统一管理,所以只需要对CookieJar进行设置就可以达到目的了。

解决:

OkHttpClient mHttpClient = new OkHttpClient.Builder().cookieJar(new CookieJar() {

private final HashMap> cookieStore = new HashMap<>();

//Tip:key是String类型且为url的host部分

@Override

public void saveFromResponse(HttpUrl url, List cookies) {

cookieStore.put(url.host(), cookies);

}

@Override

public List loadForRequest(HttpUrl url) {

List cookies = cookieStore.get(url.host());

return cookies != null ? cookies : new ArrayList();

}

}).build();

问题3:如何实现Cookies持久化?

方案1:使用PersistentCookieJar

在Project的Build.gradle中添加Maven库

allprojects {

repositories {

...

maven { url "https://jitpack.io" }

}

}

在引入依赖库

compile 'com.github.franmontiel:PersistentCookieJar:v0.9.3'

创建并使用PersistentCookieJar

ClearableCookieJar cookieJar =

new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(context));

OkHttpClient okHttpClient = new OkHttpClient.Builder()

.cookieJar(cookieJar)

.build();

方案2:参考android-async-http库写一个

参考两个类,一个是 PersistentCookieStore.java,另一个是 SerializableCookie.java。参见参考文档中的 OkHttp3实现Cookies管理及持久化,里面已经够详细了。

问题4:NetworkOnMainThreadException

下面这段代码似乎没错,不是说OkHttp会在线程池中访问网络吗?怎么会报这种错误??

@Override

protected void onResume() {

super.onResume();

Request request = new Request.Builder()

.url("https://github.com")

.build();

okHttpClient.newCall(request).enqueue(new Callback() {

@Override

public void onFailure(Call call, IOException e) {

}

@Override

public void onResponse(Call call, final Response response) throws IOException {

runOnUiThread(new Runnable() {

@Override

public void run() {

try {

String string = response.body().string(); //注意

helloTxt.setText(string);

} catch (IOException e) {

e.printStackTrace();

}

}

});

}

});

}

解决:在标注的那一行 response.body().string(),是在主线程中运行的,从响应中获取响应体属于网络操作,所以报错。解决方法是将这一行移到 runOnUiThread 方法前面。

参考文档

你可能感兴趣的:(ip,okhttp,设置)