>
前言: 今日付出的汗水,只为明日不一样的自己。唯有坚持不懈的努力,才能过上自己想要的生活
转载请标明出处:
http://blog.csdn.net/w690333243/article/details/78609258
更多内容请访问【-小沫-专栏】
注意:
OKHttp的CallBack接口中的onResponse和onFailure是在子线程中执行的
而 Retrofit的CallBack接口中的onResponse和onFailure是在主线程中执行的
https://www.jianshu.com/p/cb4c25977198
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0915/3460.html
https://blog.csdn.net/honghailiang888/article/details/54341486 【Android实战】----Android Retrofit是怎么将回调函数放到UI线程(主线程)中的(源码分析)
https://blog.csdn.net/liu81952438/article/details/69643494 OkHttp 执行流程与为什么Callback在子线程中执行
https://blog.csdn.net/dxt8305/article/details/84067538 Android把okhttp的返回数据放在主线程处理(切换线程)
https://www.jianshu.com/p/df0ff5ab5f25 OkHttp3(三)–CallbackToMainThread回调回UI线程
http://www.cnblogs.com/qlky/p/7246331.html Retrofit网络请求,工具类的封装
https://blog.csdn.net/qq_26064283/article/details/54646605
https://www.jianshu.com/p/05bbf3aa2269
https://www.jianshu.com/p/ee50751b9bd1
https://blog.csdn.net/jarchie520/article/details/78794115
https://www.jianshu.com/p/1ac372af38cd
https://blog.csdn.net/lyhhj/article/details/51720296
https://www.jianshu.com/p/1434b6da33e3
https://www.jianshu.com/p/20169c5b2575
#一、如果想要打印okhttp的log
则logging-interceptor版本要和okhttp版本保持一致
如:
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
compile 'com.squareup.okhttp3:okhttp:3.4.1'
否则报错:
Process: com.demo.okhttp, PID: 25567
java.lang.NoClassDefFoundError: Failed resolution of: Lokhttp3/internal/Platform;
at okhttp3.logging.HttpLoggingInterceptor$Logger$1.log(HttpLoggingInterceptor.java:109)
at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:157)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:147)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.ClassNotFoundException: Didn't find class "okhttp3.internal.Platform" on path: DexPathList[[zip file "/data/app/com.demo.okhttp-2/base.apk", zip file "/data/app/com.demo.okhttp-2/split_lib_dependencies_apk.apk", zip file "/data/app/com.demo.okhttp-2/split_lib_slice_0_apk.apk", zip file "/data/app/com.demo.okhttp-2/split_lib_slice_1_apk.apk", zip file "/data/app/com.demo.okhttp-2/split_lib_slice_2_apk.apk", zip file "/data/app/com.demo.okhttp-2/split_lib_slice_3_apk.apk", zip file "/data/app/com.demo.okhttp-2/split_lib_slice_4_apk.apk", zip file "/data/app/com.demo.okhttp-2/split_lib_slice_5_apk.apk", zip file "/data/app/com.demo.okhttp-2/split_lib_slice_6_apk.apk", zip file "/data/app/com.demo.okhttp-2/split_lib_slice_7_apk.apk", zip file "/data/app/com.demo.okhttp-2/split_lib_slice_8_apk.apk", zip file "/data/app/com.demo.okhttp-2/split_lib_slice_9_apk.apk"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
......
at java.lang.Thread.run(Thread.java:818)
Suppressed: java.lang.ClassNotFoundException: okhttp3.internal.Platform
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
打印log时,添加依赖代码
然后在创建OkHttpClient对象的代码中添加其拦截器实例,代码如下:
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor()).build();
这样就完成了。然后你就可以看到类似这样的日志了:
W/OkHttp: [4 request]--> GET https://api.github.com/users/defunkt http/1.1
W/OkHttp: [4 request]--> END GET
W/OkHttp: [5 request]--> GET https://api.github.com/zen http/1.1
W/OkHttp: [5 request]--> END GET
W/OkHttp: [6 request]--> GET https://api.github.com/users/msdx http/1.1
W/OkHttp: [6 request]--> END GET
W/OkHttp: [4 response]<-- 200 OK https://api.github.com/users/defunkt (1335ms)
W/OkHttp: [4 response]Server: GitHub.com
W/OkHttp: [4 response]Date: Thu, 12 Jan 2017 04:01:43 GMT
W/OkHttp: [4 response]Content-Type: application/json; charset=utf-8
W/OkHttp: [4 response]Transfer-Encoding: chunked
https://www.jianshu.com/p/e044cab4f530
http://blog.csdn.net/maosidiaoxian/article/details/77972699
#二、response.body().contentLength() = -1
遇到response.body().contentLength() = -1时,打印okhttp log会发现http响应中有Transfer-encoding
解决办法:服务端使用response.setContentLength(),传入文件大小参数,但是有个问题,setContentLength()中参数类型时int型的,故受int最大值的限制。
再次查阅资料:
参考:
http://www.mamicode.com/info-detail-1329765.html
https://zhidao.baidu.com/question/198114215.html
最终解决办法:
在服务端设置
response.setHeader("Content-Length",String.valueOf(file.length()));
请帮我回答stackoverflow中的这个问题,以帮助更多的人,我没有翻墙账号,谢谢
https://stackoverflow.com/questions/42199020/custom-retrofit-2-1-response-body-getting-contentlenth-as-1
因为okhttp中的response.body().contentLength()是读取响应头中的Content-Length字段来设置的,并不是阻塞加载整个文件后获取的文件大小
看okhttp源码
@Override public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
RequestBody body = userRequest.body();
if (body != null) {
MediaType contentType = body.contentType();
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString());
}
long contentLength = body.contentLength();
if (contentLength != -1) {
requestBuilder.header("Content-Length", Long.toString(contentLength));
requestBuilder.removeHeader("Transfer-Encoding");
} else {
requestBuilder.header("Transfer-Encoding", "chunked");
requestBuilder.removeHeader("Content-Length");
}
}
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive");
}
// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
// the transfer stream.
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies));
}
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}
Response networkResponse = chain.proceed(requestBuilder.build());
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
if (transparentGzip
&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse)) {
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
responseBuilder.headers(strippedHeaders);
String contentType = networkResponse.header("Content-Type");
responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
}
return responseBuilder.build();
}
#三、打印okhttp log时,在下载文件过程中卡顿
在做下载文件功能时,加了拦截日志监听,会发现点击下载按钮后,过了一段时间(下载的文件比稍微大点<55MB>)进度条才开始执行,后来找打一篇文章,里面隐约看到和log有关,说是开启log监听的话,会把整个文件加入内存。去掉log监听后,点击下载,进度条立即就可以执行了。
https://stackoverflow.com/questions/39545629/noclassdeffounderror-failed-resolution-of-lokhttp3-internal-platform
http://blog.csdn.net/yankai0219/article/details/8269922
http://blog.csdn.net/liwujun11111/article/details/52170337
http://blog.csdn.net/huntcode/article/details/47016529
http://blog.csdn.net/kmyhy/article/details/6032237
No Network Security Config specified
不用管这个,数据已经返回了
/**
* 初始化Retrofit
*/
private void initRetrofit() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
// 设置超时
builder.connectTimeout(TIMEOUT, TimeUnit.SECONDS);
builder.readTimeout(TIMEOUT, TimeUnit.SECONDS);
builder.writeTimeout(TIMEOUT, TimeUnit.SECONDS);
builder.retryOnConnectionFailure(true);
if (BuildConfig.DEBUG) {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(loggingInterceptor);
}
OkHttpClient okHttpClient = builder.build();
Log.i(TAG, "initRetrofit: BASE_URL:"+BASE_URL);
mRetrofit = new Retrofit.Builder()
// 设置请求的域名
.baseUrl(BASE_URL)//BASE_URL
// 设置解析转换工厂,用自己定义的
.addConverterFactory(ResponseConvert.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(okHttpClient)
.build();
}