当前位置:   article > 正文

Android#OkHttp3使用指南_persistentcookiejar

persistentcookiejar

知识框架(脑图)

Okhttp3脑图

出现背景

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

解决思路

  1. 提供了对 HTTP/2 和 SPDY 的支持,这使得对同一个主机发出的所有请求都可以共享相同的套接字连接
  2. 如果 HTTP/2 和 SPDY 不可用,OkHttp 会使用连接池来复用连接以提高效率
  3. 提供了对 GZIP 的默认支持来降低传输内容的大小
  4. 提供了对** HTTP 响应的缓存机制**,可以避免不必要的网络请求
  5. 当网络出现问题时,OkHttp 会自动重试一个主机的多个 IP 地址

OkHttp3设计思路

具体步骤

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

<uses-permission android:name="android.permission.INTERNET" />
compile 'com.squareup.okhttp3:okhttp:3.4.1'

(2)GET

  1. OkHttpClient client = new OkHttpClient();
  2. String run(String url) throws IOException {
  3. Request request = new Request.Builder()
  4. .url(url)
  5. .build();
  6. Response response = client.newCall(request).execute();
  7. return response.body().string();
  8. }

(3)POST

  1. public static final MediaType JSON
  2. = MediaType.parse("application/json; charset=utf-8");
  3. OkHttpClient client = new OkHttpClient();
  4. String post(String url, String json) throws IOException {
  5. RequestBody body = RequestBody.create(JSON, json);
  6. Request request = new Request.Builder()
  7. .url(url)
  8. .post(body)
  9. .build();
  10. Response response = client.newCall(request).execute();
  11. return response.body().string();
  12. }

(3)异步调用

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

  1. private Handler mHandler;
  2. private TextView mTxt;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_home);
  7. mTxt = (TextView) findViewById(R.id.txt);
  8. mHandler = new Handler(Looper.getMainLooper()){
  9. @Override
  10. public void handleMessage(Message msg) {
  11. mTxt.setText((String) msg.obj);
  12. }
  13. };
  14. OkHttpClient client = new OkHttpClient();
  15. Request request = new Request.Builder().url("https://github.com").build();
  16. client.newCall(request).enqueue(new Callback() {
  17. @Override
  18. public void onFailure(Call call, IOException e) {
  19. }
  20. @Override
  21. public void onResponse(Call call, Response response) throws IOException {
  22. Message msg = new Message();
  23. msg.what=0;
  24. msg.obj = response.body().string();
  25. mHandler.sendMessage(msg);
  26. }
  27. });
  28. }

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

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

  • 使用header(name,value)来设置HTTP头的唯一值
  • 使用addHeader(name,value)来补充新值
  • 使用header(name)读取唯一值或多个值的最后一个值
  • 使用headers(name)获取所有值
  1. OkHttpClient client = new OkHttpClient();
  2. Request request = new Request.Builder()
  3. .url("https://github.com")
  4. .header("User-Agent", "My super agent")
  5. .addHeader("Accept", "text/html")
  6. .build();
  7. Response response = client.newCall(request).execute();
  8. if (!response.isSuccessful()) {
  9. throw new IOException("服务器端错误: " + response);
  10. }
  11. System.out.println(response.header("Server"));
  12. System.out.println(response.headers("Set-Cookie"));

(5)表单提交

  1. RequestBody formBody = new FormEncodingBuilder()
  2. .add("query", "Hello")
  3. .build();

(6)文件上传

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

  1. MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
  2. RequestBody requestBody = new MultipartBuilder()
  3. .type(MultipartBuilder.FORM)
  4. .addPart(
  5. Headers.of("Content-Disposition", "form-data; name=\"title\""),
  6. RequestBody.create(null, "测试文档"))
  7. .addPart(
  8. Headers.of("Content-Disposition", "form-data; name=\"file\""),
  9. RequestBody.create(MEDIA_TYPE_TEXT, new File("input.txt")))
  10. .build();

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

  1. OkHttpClient client = new OkHttpClient();
  2. final MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
  3. final String postBody = "Hello World";
  4. RequestBody requestBody = new RequestBody() {
  5. @Override
  6. public MediaType contentType() {
  7. return MEDIA_TYPE_TEXT;
  8. }
  9. @Override
  10. public void writeTo(BufferedSink sink) throws IOException {
  11. sink.writeUtf8(postBody);
  12. }
  13. @Override
  14. public long contentLength() throws IOException {
  15. return postBody.length();
  16. }
  17. };
  18. Request request = new Request.Builder()
  19. .url("http://www.baidu.com")
  20. .post(requestBody)
  21. .build();
  22. Response response = client.newCall(request).execute();
  23. if (!response.isSuccessful()) {
  24. throw new IOException("服务器端错误: " + response);
  25. }
  26. System.out.println(response.body().string());

(8)缓存控制

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

  1. Request request = new Request.Builder()
  2. .cacheControl(new CacheControl.Builder().noCache().build())
  3. .url("http://publicobject.com/helloworld.txt")
  4. .build();

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

  1. Request request = new Request.Builder()
  2. .cacheControl(new CacheControl.Builder()
  3. .maxAge(0, TimeUnit.SECONDS)
  4. .build())
  5. .url("http://publicobject.com/helloworld.txt")
  6. .build();

强制缓存,关键:onlyIfCached()

  1. Request request = new Request.Builder()
  2. .cacheControl(new CacheControl.Builder()
  3. .onlyIfCached()
  4. .build())
  5. .url("http://publicobject.com/helloworld.txt")
  6. .build();
  7. Response forceCacheResponse = client.newCall(request).execute();
  8. if (forceCacheResponse.code() != 504) {
  9. // The resource was cached! Show it.
  10. } else {
  11. // The resource was not cached.
  12. }

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

  1. Request request = new Request.Builder()
  2. .cacheControl(new CacheControl.Builder()
  3. .maxStale(365, TimeUnit.DAYS)
  4. .build())
  5. .url("http://publicobject.com/helloworld.txt")
  6. .build();

Q&A

问题1:CalledFromWrongThreadException怎么破?

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

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

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

  1. OkHttpClient mHttpClient = new OkHttpClient.Builder().cookieJar(new CookieJar() {
  2. private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
  3. //Tip:keyString类型且为url的host部分
  4. @Override
  5. public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
  6. cookieStore.put(url.host(), cookies);
  7. }
  8. @Override
  9. public List<Cookie> loadForRequest(HttpUrl url) {
  10. List<Cookie> cookies = cookieStore.get(url.host());
  11. return cookies != null ? cookies : new ArrayList<Cookie>();
  12. }
  13. }).build();

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

方案1:使用PersistentCookieJar

在Project的Build.gradle中添加Maven库

  1. allprojects {
  2. repositories {
  3. ...
  4. maven { url "https://jitpack.io" }
  5. }
  6. }

在引入依赖库

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

创建并使用PersistentCookieJar

  1. ClearableCookieJar cookieJar =
  2. new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(context));
  3. OkHttpClient okHttpClient = new OkHttpClient.Builder()
  4. .cookieJar(cookieJar)
  5. .build();

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

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

问题4:NetworkOnMainThreadException

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

  1. @Override
  2. protected void onResume() {
  3. super.onResume();
  4. Request request = new Request.Builder()
  5. .url("https://github.com")
  6. .build();
  7. okHttpClient.newCall(request).enqueue(new Callback() {
  8. @Override
  9. public void onFailure(Call call, IOException e) {
  10. }
  11. @Override
  12. public void onResponse(Call call, final Response response) throws IOException {
  13. runOnUiThread(new Runnable() {
  14. @Override
  15. public void run() {
  16. try {
  17. String string = response.body().string(); //注意
  18. helloTxt.setText(string);
  19. } catch (IOException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. });
  24. }
  25. });
  26. }

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

参考文档

  1. OkHttp:Java 平台上的新一代 HTTP 客户端
  2. OkHttp
  3. 拆轮子系列:拆 OkHttp
  4. OkHttp3实现Cookies管理及持久化


转载自:https://www.jianshu.com/p/457d3ab27584
 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/45662
推荐阅读
相关标签
  

闽ICP备14008679号