自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
List headerStrings=response.headers(“Vary”);
Log.i(TAG,headerString);
Iterator it=headerStrings.iterator();
while (it.hasNext()) {
Log.i(TAG,it.next());
}
Post提交String
以下例子使用https://reqres.in测试请求:
private static final MediaType JSON = MediaType.parse(“application/json; charset=utf-8”);
String url = “https://reqres.in/api/users/”;
String jsonString = “{\n” +
" “name”: “morpheus”,\n" +
" “job”: “leader”\n" +
“}”;
private void post(String url, final String requestString) {
RequestBody requestBody = RequestBody.create(JSON, requestString);
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
mClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
call.cancel();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String responseString = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText(responseString);
}
});
}
});
}
Post提交表单
final String url = “https://tieba.baidu.com/f”;
RequestBody requestBody = new FormBody.Builder()
.add(“ie”, “utf-8”)
.add(“kw”, “minecraft”)
.build();
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
Post提交文件
public static final MediaType JPEG = MediaType.parse(“image/jpeg”);
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM), “building.jpg”);
RequestBody requestBody = RequestBody.create(JPEG, file);
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
Post提交流
RequestBody requestBody = new RequestBody() {
@Nullable
@Override
public MediaType contentType() {
return null;
}
@Override
public void writeTo(@NotNull BufferedSink bufferedSink) throws IOException {
bufferedSink.writeUtf8(requestString);
}
};
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
使用Gson解析response
String url = “https://api.github.com/gists/c2a7c39532239ff261be”;
class Gist{
Map<String,GistFile> files;
}
class GistFile{
String content;
}
Gson gson = new Gson();
Gist gist = gson.fromJson(response.body().charStream(),Gist.class);
for(Map.Entry<String,GistFile> entry:gist.files.entrySet()){
Log.i(TAG,entry.getKey()+ " "+entry.getValue().content);
}
设置超时
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(3, TimeUnit.SECONDS)
.build();
配置新client
.newBuilder()
会返回一个配置相同的buidler
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(3, TimeUnit.SECONDS)
.build();
OkHttpClient client2 = client.newBuilder()
.connectTimeout(5, TimeUnit.SECONDS)
.build();
拦截器
拦截器(Interceptor
)是OkHttp的概念,也是核心功能。OkHttp有两种拦截器,分别是应用拦截器和网络拦截器。拦截器的主要目的在于重写request
和response
,可以在发出request
前修改headers或body,也可以在收到response
前修改headers或body。我们完全可以在用户收到reponse
前将其修改成一个完全不一样的新response
,这一功能使得我们可以进行后续的缓存策略修改或是使用gzip压缩requestBody等操作。应用拦截器在用户发出一次请求后的全过程中仅调用一次,而网络拦截器可能因为重定向等问题多次调用,例如有一次重定向就会调用两次。拦截器可以设置多个,并按添加顺序进行拦截。下图来自OkHttp文档:
两种拦截器区别如下,参考OkHttp文档原文:
Application interceptors
- Don’t need to worry about intermediate responses like redirects and retries.
- Are always invoked once, even if the HTTP response is served from the cache.
- Observe the application’s original intent. Unconcerned with OkHttp-injected headers like
If-None-Match
.- Permitted to short-circuit and not call
Chain.proceed()
.- Permitted to retry and make multiple calls to
Chain.proceed()
.- Can adjust
Call
timeouts usingwithConnectTimeout
,withReadTimeout
,withWriteTimeout
.Network Interceptors
- Able to operate on intermediate responses like redirects and retries.
- Not invoked for cached responses that short-circuit the network.
- Observe the data just as it will be transmitted over the network.
- Access to the
Connection
that carries the request.
个人翻译如下:
应用拦截器
- 使用时不需要考虑例如重定向、重试等中转请求带来的影响
- 全过程只拦截一次,即使拦截的
response
来自缓存- 可处理来自Applcation(参考拦截器图解)的本意。(例如
no-cache
)不涉及OkHttp的头部注入例如If-None-Match
头部(这是在core注入的)- 可以不调用
Chain.proceed()
(例如return
一个来自缓存的response
,但不能return null
)- 可以重试和多次调用
Chain.proceed()
- 可通过
withConnectTimeout
,withReadTimeout
,withWriteTimeout
调整Call
的超时时间.网络拦截器
- 可处理例如重定向、重试等中转请求
- 不涉及缓存的调用
- 可处理来自服务器的原始响应
- 可对最终发出前的请求做读写
- 实现拦截器
以上所说拦截器可对处于中间时期的request
和response
做修改,就是在chain.proceed(request)
的前后完成的。
chain.proceed(request)
会返回通过core或服务器处理后得到的response
,这个方法会阻塞线程。
String url = “http://publicobject.com/helloworld.txt”;
class LoggingInterceptor implements Interceptor {
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
//do something to rewrite request
long t1 = System.nanoTime();
Log.i(TAG,String.format(“Sending request %s on %s%n%s”,
request.url(), chain.connection(), request.headers()));
Response response = chain.proceed(request);
long t2 = System.nanoTime();
Log.i(TAG,String.format(“Received response for %s in %.1fms%n%s”,
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
//do something to rewrite response
return response;
}
}
- 设置应用拦截器
两种拦截器在实现的时候没有区别,充当那种拦截器取决于调用的方法是.addInterceptor()
或是.addNetworkInterceptor()
。.addInterceptor()
表示设置应用拦截器,.addNetworkInterceptor()
则是网络拦截器。
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();
- 设置网络拦截器
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new LoggingInterceptor())
.build();
缓存处理
OkHttp默认不使用缓存,可以调用.cache()
开启,但.cache()
仅能设置缓存区大小和缓存读写的位置。Cache-Control
头部是Http协议定义的,而OkHttp完全遵循Http协议,所以OkHttp的缓存策略是由请求头或响应头中的Cache-Control
头部而定的。如果服务器返回的response
已经带有Cache-Control响应头,在buidler中调用.cache()
即可使用缓存。反之当收到的response
没有设置Cache-Control
时,可以在拦截器里手动添加,不同参数对应不同的缓存策略。不论response
是否有Cache-Control
,始终可以在发出request
时添加例如Cache-control: no-cache
来控制缓存使用与否。
启用缓存
String url = “http://publicobject.com/helloworld.txt”;
int _10MB = 10 * 1024 * 1024;
File cacheDir = getCacheDir();
Cache cache = new Cache(cacheDir, _10MB);
OkHttpClient client = new OkHttpClient.Builder()
.cache(cache)
.build();
缓存策略
Http协议的Cache-Control
的参数有很多,可设置多个参数,多个参数间用逗号分隔开。以下主要介绍其中几种的含义
Cache-Control: max-age=3600
设置缓存过期时间为一小时。单位为秒,用于response
Cache-Control: max-stale=3600
表示接受使用过期的缓存,最长时间为过期后的一小时,单位为秒。用于request
Cache-control: no-cache
先不使用本地缓存,向服务器验证缓存是否过期后决定缓存使用与否,且并不取消本次response
的缓存。用于request
Cache-control: no-store
本次请求不缓存得到的response,也表示本次请求不读取缓存。用于request
Cache-control: only-if-cached
仅尝试使用缓存。用于request
Cache-control: public
表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存,即使是通常不可缓存的内容。(例如该响应没有max-age
指令或Expires
消息头, 该响应对应的请求方法是 POST )Cache-control: private
表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)。私有缓存可以缓存响应内容,比如:对应用户的本地浏览器。Cache-Control: min-fresh=3600
表示客户端希望获取一个能在指定的秒数内保持其最新状态的响应。Cache-control: must-revalidate
一旦资源过期(比如已经超过max-age
),在成功向原始服务器验证之前,缓存不能用该资源响应后续请求。
此外与缓存有关的header可能还有Expires
和Pragma
,这里暂不介绍
- 直接修改Cache-Control头部定义缓存策略
class CacheInterceptor implements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
request = request.newBuilder()
.header(“Cache-Control”, “max-stale=3600”)
.build();
return chain.proceed(request);
}
}
Interceptor interceptor = new CacheInterceptor();
mClient = new OkHttpClient.Builder()
.cache(cache)
.addInterceptor(interceptor)
.build();
- 使用CacheControl.Builder()定义缓存策略
CacheControl
类只能在拦截器中使用,其实质只是在请求头或响应头为Cache-Control
添加不同的参数而已,并没有其他作用
class ForceCacheInterceptor implements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
CacheControl cacheControl = new CacheControl.Builder()
.onlyIfCached()
.build();
request = request.newBuilder()
.cacheControl(cacheControl)
.build();
return chain.proceed(request);
}
}
Interceptor interceptor = new ForceCacheInterceptor();
mClient = new OkHttpClient.Builder()
.cache(cache)
.addInterceptor(interceptor)
.build();
CacheControl.Builder的常用方法
- .maxAge(3600, TimeUnit.SECONDS);
- .maxStale(3600, TimeUnit.SECONDS);
- .noCache();
- .noStore();
- .onlyIfCached();
含义参考Cache-Control
参数介绍
- 使用CacheControl的伴生对象定义缓存策略
CacheControl
的伴生对象有两个,CacheControl.FORCE_CACHE
和CacheControl.FORCE_NETWORK
,分别表示强制使用缓存和强制使用网络。
public class ForceNetworkInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
if (!NetworkUtils.internetAvailable()) {
builder.cacheControl(CacheControl.FORCE_NETWORK);
}
return chain.proceed(builder.build());
}
}
分享读者
作者2013年java转到Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。
被人面试过,也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!
我们整理了一份阿里P7级别的Android架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。
主要包括阿里,以及字节跳动,腾讯,华为,小米,等一线互联网公司主流架构技术。如果你有需要,尽管拿走好了。
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。
主要包括阿里,以及字节跳动,腾讯,华为,小米,等一线互联网公司主流架构技术。如果你有需要,尽管拿走好了。
[外链图片转存中…(img-GnW9Enkx-1715005317261)]
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!