android使用okhttp3

官网
官方github
官方文档

快速使用

  1. 添加依赖
  2. 添加权限
    1
    <uses-permission android:name="android.permission.INTERNET" />

get使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
String url = "https://www.baidu.com";
OkHttpClient client = new OkHttpClient.Builder()
.callTimeout(5,TimeUnit.SECONDS)
.readTimeout(10,TimeUnit.SECONDS)
.writeTimeout(10,TimeUnit.SECONDS)
.build();
Request request = new Request.Builder()
.get()
.addHeader("name","value")
.url(url)
.build();

//enqueue是异步调用,同步是excute,但是Android不能使用
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//失败了调用的方法
Log.e(TAG, "失败了: ",e );
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//成功了调用的方法
Log.d(TAG, "onResponse: "+response.body().string());
if(response.body()!=null){
response.body().close();
}
}
});

OkHttpClient是创建一个连接,并且设置了连接超时时间和读取超时时间,以及写入超时时间

Request是构造了一个请求

  • get是请求方式
  • url是请求的url
  • addHeader添加header

其中成功的回掉中有一个response参数,他是服务器返回的response

  • .body()获取response的body部分的值,通常调用.body().string()获取具体内容经过我测试,body().string()方法使用一次后再次使用会报错,所以最好先取出来字符串然后进行操作
  • .isRedirect()判断是不是重定向,其实就是判断状态码是不是重定向的状态码
  • .isSuccessful()判断是不是获取成功了,其实就是判断状态码是不是成功的200
  • enqueue()是异步调用,如果涉及到更新ui,应该使用runOnUiThread或者其他的线程通信方法

post请求

form请求

1
2
3
4
5
6
7
8
9
RequestBody requestBody = new FormBody.Builder()
.add("user","zhangsan")
.add("pass","123456")
.build();
Request request = new Request.Builder()
.post(requestBody)
.addHeader("name","value")
.url(url)
.build();

只需要用FromBody实例化一个RequestBody,然后构建request时候把get()改成post(requestBody)即可

json方式请求

post请求和上面一样,不同的是创建RequestBody的方法

1
2
String json = "{\"username\":\"zhangsan\"}";
RequestBody requestBody = RequestBody.create(MediaType.get("application/json"),json);

拦截器

Okhttp-wiki 之 Interceptors 拦截器

拦截器就是拦截网络请求与响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyInterceptor implements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
Log.d("tagtag", String.format("Sending request %s on %s%n%s",request.url(), chain.connection(), request.headers()));

//放行获取response
Response response = chain.proceed(request);
long t2 = System.nanoTime();
Log.d("tagtag", String.format("Received response for %s in %.1fms%n%s",response.request().url(), (t2 - t1) / 1e6d, response.headers()));
return response;
}
}

添加应用拦截器

1
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new MyInterceptor()).build();

添加网络拦截器

1
OkHttpClient client = new OkHttpClient.Builder().addNetworkInterceptor(new MyInterceptor()).build();

应用拦截器和网络拦截器的区别

应用拦截器和网络拦截器的区别
上面的拦截器是应用拦截器,下面的拦截器是网络拦截器
网络拦截器能拦截所有的网络请求,应用拦截器只能拦截应用发出和最后收到的请求和响应

打个比方:

访问a地址,a地址会重定向到b
那么此时网络拦截器能拦截到发送到a的request和返回a的response和发送给b的request和b返回的response
应用拦截器只会拦截到发送给a的request和b返回的response

文件下载

简单方式

和上面get方式差不多,只不过不是获取response.body().string(),而是获取response的字节流,通过字节流写入到文件中
先加入文件读写的权限

1
2
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
OkHttpClient client = new OkHttpClient.Builder()
.build();
String url = "https://www.imooc.com/mobile/mukewang.apk";
Request request = new Request.Builder().get()
.url(url)
.build();

client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//失败了调用的方法
Log.e(TAG, "失败了: ", e);
}

@Override
public void onResponse(Call call, Response response) throws IOException {
writeFile(response);
}
});

private void writeFile(Response response) {
InputStream inputStream = null;
FileOutputStream fileOutputStream = null;

String filePath = Environment.getExternalStorageDirectory().getAbsolutePath();
File file = new File(filePath, "mukewang.apk");
try {
//获取response的数据流
inputStream = response.body().byteStream();
//创建本地文件
fileOutputStream = new FileOutputStream(file);

//设置缓存字节流
byte[] bytes = new byte[1024];
int len = 0;
//获取文件总大小
long filesize = response.body().contentLength();

//已经下载文件的大小
long sum =0;

while ((len = inputStream.read(bytes)) != -1) {
//把获取的写入
fileOutputStream.write(bytes,0,len);
//当前已经下载的文件大小
sum+=len;
//计算百分比
final int progress = (int)(sum*100/filesize);
runOnUiThread(new Runnable() {
@Override
public void run() {
progressBar.setProgress(progress);
}
});

}
fileOutputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "完成啦", Toast.LENGTH_SHORT).show();
}
});
}

其中还调用了设置了一个progressBar显示长度

使用拦截器获取下载进度

写一个接口,设置progress的值,让activity实现这个接口

1
2
3
4
public interface ProgressListenere {
void sendProgress(int i);
void done();
}

重写ResponseBody,在这里面获取下载的进度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class MyResponseBody extends ResponseBody {
private ResponseBody mResponseBody;
private BufferedSource mBufferedSource;
private ProgressListenere mProgressListenere;

public MyResponseBody(ResponseBody mResponseBody, ProgressListenere mProgressListenere) {
this.mResponseBody = mResponseBody;
this.mProgressListenere = mProgressListenere;
}
@Override
public MediaType contentType() {
return mResponseBody.contentType();
}
@Override
public long contentLength() {
return mResponseBody.contentLength();
}
@Override
public BufferedSource source() {
if(mBufferedSource==null){
mBufferedSource=Okio.buffer(getSource(mResponseBody.source()));
}
return mBufferedSource;
}
private Source getSource(Source source){
return new ForwardingSource(source) {
long allSize=0;
long sum=0;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
if(allSize==0){
allSize = contentLength();
}
long len = super.read(sink, byteCount);
sum+=(len>0?len:0);
int progress=(int)(sum*100/allSize);
if(len==-1){
mProgressListenere.done();
}else{
mProgressListenere.sendProgress(progress);
}
return len;
}
};
}
}

mainactivity中和上面差不多,只不过设置进度条的那部分不用写了,然后个构建client的时候要写一个网络拦截器,里面加载刚刚写的ResponseBody

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
OkHttpClient client =  new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
return response.newBuilder().body(new MyResponseBody(response.body(),MainActivity.this)).build();
}
})
.build();
String url = "https://www.imooc.com/mobile/mukewang.apk";
Request request = new Request.Builder().get()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(TAG, "失败了: ", e);
}

@Override
public void onResponse(Call call, Response response) throws IOException {
writeFile(response);
}
});
private void writeFile(Response response) {
InputStream inputStream = null;
FileOutputStream fileOutputStream = null;

String filePath = Environment.getExternalStorageDirectory().getAbsolutePath();
File file = new File(filePath, "mukewang.apk");
try {
inputStream = response.body().byteStream();
fileOutputStream = new FileOutputStream(file);
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes,0,len);
}
fileOutputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

处理cookies

构建client的时候调用cookieJar方法实现一个CookieJar,saveFromResponse是用于保存网页上传回来的List,loadForRequest是发送一个List

1
2
3
4
5
6
7
8
9
10
11
12
OkHttpClient client =  new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {

}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
return null;
}
})
.build();

如果cookie为空,返回一个空的list,不能返回null
如果想要保持session,则需要保存cookie中对应的sessionid即可

设置缓存

1
2
3
4
int cachesize = 10*1024*1024;
OkHttpClient client = new OkHttpClient.Builder()
.cache(new Cache(getExternalCacheDir().getAbsoluteFile(),cachesize))
.build();

之前写的Java使用okhttp3

使用get访问url,使用json和text的方式posturl

要引入okhttp和okio还有阿里巴巴的fastjson的jar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import java.io.IOException;
import java.util.Iterator;
import java.util.Set;

import com.alibaba.fastjson.JSONObject;

import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class HttpUtils {

private static OkHttpClient client = new OkHttpClient();

public static String get(String url) throws IOException {

Request request = new Request.Builder().url(url).build();

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

if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
}

// data例子:a=b&=c
public static String Posttext(String url, String data) {
String[] datas = data.split("&");
FormBody.Builder builder = new FormBody.Builder();
for (String dataa:datas) {
builder.add(dataa.split("=")[0],dataa.split("=")[1]);
}
RequestBody requestBody = builder.build();
return Post(url,requestBody);
}
//data例子 {a:b,c:d}
public static String Postjson(String url,String json) {
FormBody.Builder builder = new FormBody.Builder();
JSONObject jsonobject = JSONObject.parseObject(json);
Set<String> keySet = jsonobject.keySet();
Iterator<String> it = keySet.iterator();
while(it.hasNext()) {
String a = it.next();
String b = jsonobject.getString(a);
builder.add(a, b);
}
RequestBody requestBody = builder.build();
return Post(url,requestBody);
}
public static String Post(String url,RequestBody requestBody) {
String result = null;
Request request = new Request.Builder().url(url).post(requestBody).build();
try {
Response response = client.newCall(request).execute();
result = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}

public static void main(String[] args) throws IOException {
System.out.println(get("http://localhost:8080/Qcb/FriendZoneServlet"));
String json = "{\"context\":\"ccc\",\"icon\":\"aaaa\",\"name\":\"bbb\"}";
System.out.println(Postjson("http://localhost:8080/Qcb/FriendZoneServlet", json));
System.out.println(Posttext("http://localhost:8080/Qcb/FriendZoneServlet", "icon=abc&name=def&context=ghi"));

}
}