1.支持HTTP/2,允许多个请求共享一个socket连接。
2.减少请求延时。
3.GZIP压缩服务器响应数据的大小等。
ps:详情请关注官网,我在使用中也只是比赛时研究过一段时间,将爬坑经历写在微博上供大家参考。
package com.example.hgz.myapplication;
import android.util.Log;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class OkHttpUtils {
private String backInfo;
public String getInfo(String url) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d("info:", "filed");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
Log.d("info:", "success");
Log.d("code:", "response.code()==" + response.code());
backInfo= response.body().string();
// 请勿多次调用 response.body().string() 会出现: java.lang.IllegalStateException: closed错
Log.d("ResponseBody:", "response.body().string()==" + backInfo);
}
}
});
return backInfo;
}
public String postInfo(String url,String json){
OkHttpClient client = new OkHttpClient();//创建OkHttpClient对象。
MediaType JSON = MediaType.parse("application/json; charset=utf-8");//数据类型为json格式,
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d("info:", "filed");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {//回调的方法执行在子线程。
Log.d("info:", "success");
Log.d("code:", "response.code()==" + response.code());
backInfo= response.body().string();
// 请勿多次调用 response.body().string() 会出现: java.lang.IllegalStateException: closed错
Log.d("ResponseBody:", "response.body().string()==" + backInfo);
}
}
});
return backInfo;
}
}
PS:这是一个封装的util,但是这个工具类仅供参考使用,可能会出现问题。
1.添加okhttp封装的okhttp的jar包和okhttp的iojar包。
或者引用github上的官网提供的依赖。
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.squareup.okio:okio:1.7.0'
ps:如需最新依赖,请去官网查阅使用。
2.最重要的是在Android的配置文件中加入网络权限:
3.在Android平台开发中,由于涉及线程安全,需要在子线程中进行网络访问,所以涉及线程方面的知识,话不多说,上代码:
package com.example.hgz.myapplication;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class OkHttpThreadTest extends Thread{
private Handler handler;
public OkHttpThreadTest(Handler handler) {
this.handler = handler;
}
@Override
public void run() {
super.run();
OkHttpUtils utils = new OkHttpUtils();
String time = utils.getInfo("http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp");
if (time!=null){
Log.e("time",time);
Bundle build = new Bundle();
build.putString("time",time);
Message message = handler.obtainMessage();
message.setData(build);
handler.sendMessage(message);
}
}
}
这里调用的是淘宝的时间API。
当然这里涉及到了如何将信息从子线程中传输到UI线程中,这里就使用了Handler消息处理机制。通过同一个对象的handler通过
handler.obtainMessage();消息池的概念进行消息传输。
4.在MainActivity中通过
class Myhandler extends Handler{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
textView.setText(msg.getData().getString("time"));
}
}
msg.getData().getString("time")通过键值对中的键来获取消息池中存放的数据。
5.最后开启线程进行跑起来。
Handler handler = new Myhandler();
new OkHttpThreadTest(handler).start();
切记一定要start()线程,不然一切无用功。
注:如果需要定时请求不断请求更新,除了设置timer定时器的方式进行,可以通过while的死循环进行,下面上修改上文线程中的代码案例:
package com.example.hgz.myapplication;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class OkHttpThreadTest extends Thread{
private Handler handler;
public OkHttpThreadTest(Handler handler) {
this.handler = handler;
}
@Override
public void run() {
super.run();
OkHttpUtils utils = new OkHttpUtils();
while (true){
try {
// 线程每隔1000毫秒执行一次
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 切记将utils写在while的死循环里面,否者emmmm你懂的
String time = utils.getInfo("http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp");
if (time!=null){
Log.e("time",time);
Bundle build = new Bundle();
build.putString("time",time);
Message message = handler.obtainMessage();
message.setData(build);
handler.sendMessage(message);
}
}
}
}
1.response.body().string();重复调用出错问题。、
java.lang.IllegalStateException: closed,我们经常会在获取值or传至的过程中打个Log或sout出来,由于有打Log的习惯,所以爆出了上述的错误,范围的response.body消息体在使用中不可以重复调用。原因很简单,我们先查看源码:
public final String string() throws IOException {
BufferedSource source = source();
try {
Charset charset = Util.bomAwareCharset(source, charset());
return source.readString(charset);
} finally {
Util.closeQuietly(source);
}
}
这是Response下的Response下的一段代码,很简洁的写出了string后已经关闭了流,所以你再次调用时,流已经关闭了,所以无法再次调用,调用出来也是抛出的异常。
ResponseBody代码:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package okhttp3;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import okhttp3.internal.Util;
import okio.Buffer;
import okio.BufferedSource;
public abstract class ResponseBody implements Closeable {
private Reader reader;
public ResponseBody() {
}
public abstract MediaType contentType();
public abstract long contentLength();
public final InputStream byteStream() {
return this.source().inputStream();
}
public abstract BufferedSource source();
public final byte[] bytes() throws IOException {
long contentLength = this.contentLength();
if (contentLength > 2147483647L) {
throw new IOException("Cannot buffer entire body for content length: " + contentLength);
} else {
BufferedSource source = this.source();
byte[] bytes;
try {
bytes = source.readByteArray();
} finally {
Util.closeQuietly(source);
}
if (contentLength != -1L && contentLength != (long)bytes.length) {
throw new IOException("Content-Length and stream length disagree");
} else {
return bytes;
}
}
}
public final Reader charStream() {
Reader r = this.reader;
return r != null ? r : (this.reader = new InputStreamReader(this.byteStream(), this.charset()));
}
public final String string() throws IOException {
return new String(this.bytes(), this.charset().name());
}
private Charset charset() {
MediaType contentType = this.contentType();
return contentType != null ? contentType.charset(Util.UTF_8) : Util.UTF_8;
}
public void close() {
Util.closeQuietly(this.source());
}
public static ResponseBody create(MediaType contentType, String content) {
Charset charset = Util.UTF_8;
if (contentType != null) {
charset = contentType.charset();
if (charset == null) {
charset = Util.UTF_8;
contentType = MediaType.parse(contentType + "; charset=utf-8");
}
}
Buffer buffer = (new Buffer()).writeString(content, charset);
return create(contentType, buffer.size(), buffer);
}
public static ResponseBody create(MediaType contentType, byte[] content) {
Buffer buffer = (new Buffer()).write(content);
return create(contentType, (long)content.length, buffer);
}
public static ResponseBody create(final MediaType contentType, final long contentLength, final BufferedSource content) {
if (content == null) {
throw new NullPointerException("source == null");
} else {
return new ResponseBody() {
public MediaType contentType() {
return contentType;
}
public long contentLength() {
return contentLength;
}
public BufferedSource source() {
return content;
}
};
}
}
}
有兴趣的小伙伴可以看看人家封装的源码,其实挺有意思的。
2.在使用工具类的回调方法中会出一大堆麻烦,贴的第一个工具类是为了高大上才整的,但是没有我下面贴的这个来的实在:
package com.jmi.jingsai;
import android.os.Handler;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Created by Huguanzhong on 2018/3/23.
*/
public class OkHttpUtil {
public String getPostInfo(String url,String json) {
String s = null;
MediaType mediaType = MediaType.parse("application/json");
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(mediaType,json);
Request request = new Request.Builder().url(url).post(body).build();
try {
Response response = client.newCall(request).execute();
String str = response.body().string();
JSONObject jsonObject = new JSONObject(str);
s = jsonObject.getString("value");
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return s;
}
public String getInfo(String url,String json) throws IOException {
String s = null;
MediaType mediaType = MediaType.parse("application/json");
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(mediaType,json);
Request request = new Request.Builder().url(url).post(body).build();
Response response = client.newCall(request).execute();
s = response.body().string();
return s;
}
public String getWeather(String url){
String s = null;
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
try {
Response response =client.newCall(request).execute();
s = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
return s;
}
}
虽然这代码写得糟,但是很实用有没有。return很轻松。
3.在线程执行时,需要在子线程中执行或者在UI线程中执行。
子线程中执行不多说了,UI线程中执行如下:
runOnUiThread(new Runnable() {
@Override
public void run() {
//执行方法
}
});
个人不建议,因为不安全。但是安全又是个宽泛的概念,具体怎样才安全,谁知道呢,对吧。这篇博客也写完了,也只是浅显的介绍一下okhttp使用和如何爬坑,因为现在在家无法访问外网,等我有机会访问外网时,会具体详细的阐述一下Okhttp的使用流程。