一.说明
虽说现在网络层框架很多,比如volley,nohttp,okhttp等等,但是目前okhttp还是用的最多的。所以说详细的了解okhttp的使用,
源码解析和okhttp的封装是十分必要的,这一系列文章将从okhttp的使用开始
OKHttp是Android版Http客户端。非常高效,支持SPDY、连接池、GZIP和 HTTP 缓存。默认情况下,OKHttp会自动处理常见的网络问题,像二次连接、SSL的握手问题。如果你的应用程序中集成了OKHttp,Retrofit默认会使用OKHttp处理其他网络层请求。另外
从Android4.4开始HttpURLConnection的底层实现采用的是okHttp。
二.使用
1.安装
gradle:
compile 'com.squareup.okhttp:okhttp:2.4.0'
compile 'com.squareup.okio:okio:1.5.0'
2.Http Get请求
//创建OkHttp请求对象
OkHttpClient client = new OkHttpClient();
//每一次网络请求都是一个Request,Request.Builder传入url,header,params,method等信息
Request request = new Request.Builder().url(url).build();
//通过request封装一个Call对象,将请求封装成任务,既然是个任务就有execute()和cancel()等方法
Call call=client.newCall(request);
//然后直接execute执行得到Response对象,这个方法是个阻塞的方法,通过Response可以得到code,message等信息。
Response response = call.execute();
if (response.isSuccessful()) {
boolean fromCache = response.cacheResponse() != null;
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
上面是同步的方式,异步的如下
//请求加入调度
call.enqueue(new Callback()
{
@Override
public void onFailure(Request request, IOException e)
{
}
@Override
public void onResponse(final Response response) throws IOException
{
//String htmlStr = response.body().string();
//InputStream is=response.body().byteStream();
}
});
onResponse执行的线程是不是ui线程,如果要操作控件,还需要通过handler
3.Post请求
上面对OkHttp的Get请求分析完之后,OkHttp的整个请求流程和处理流程就清晰,Post请求和Get请求的流程都是一样,区别只是在于Request对象构造上有区别。 (1)Post提交键值对
RequestBody body = new FormEncodingBuilder()
.add("platform", "android")
.add("name", "bug")
.add("subject", "XXXXXXXXXXXXXXX")
.build();
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
client.newCall(request).enqueue(new Callback(){});
(2)Post提交json
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
client.newCall(request).enqueue(new Callback(){})
(3)基于http的文件上传
File file = new File(Environment.getExternalStorageDirectory(), "balabala.mp4");
RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(Headers.of(
"Content-Disposition",
"form-data; name=\"mFile\";
filename=\"wjd.mp4\""), fileBody)
.build();
Request request = new Request.Builder()
.url("http://192.168.1.103:8080/okHttpServer/fileUpload")
.post(requestBody);
.build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback()
{
//...
});
通过MultipartBuilder的addPart方法可以添加键值对或者文件。
4.编码问题
在OkHttp中,无论是Get请求还是Post请求所有参数的编码方式都是默认采用UTF-8的编码方式进行编码。
所以在进行Get请求或Post请求时,文本参数都不需要我们进行手动编码,但是在服务端进行参数解析时,需要做简单的处理,这里我只说明tomcat下运行的Java后台服务的处理方式:
1.针对Get请求,我们只需要在tomcat的server.xml文件中设置默认编码方式(URIEncoding="UTF-8" )为UTF-8即可,注意此编码设置只对Get请求有效。
2.针对Post请求,我们在解析获取参数值之前需要手动设置请求的编码方式为UTF-8,如:req.setCharacterEncoding("UTF-8");
5.取消一个call
使用Call.cancel()可以立即停止掉一个正在执行的call。如果一个线程正在写请求或者读响应,将会引发IOException。
当call没有必要的时候,使用这个api可以节约网络资源。例如当用户离开一个应用时。不管同步还是异步的call都可以取消。
使用Request.Builder.tag(tag)来分配一个标签。之后你就可以用OkHttpClient.cancel(tag)来取消所有带有这个tag的call
6.设置连接和读写时间,cookie的持久化保存,https的支持,
<span style="font-family:SimSun;"> //cookie信息的持久化保存
CookieHandler cookieHandler = new CookieManager(new PersistentCookieStore(context),
CookiePolicy.ACCEPT_ALL);
//Interceptor是拦截器, 在发送之前, 添加一些参数, 或者获取一些信息.loggingInterceptor是打印参数
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
//设置缓存的文件
File httpCacheDirectory = new File(context.getExternalCacheDir(), "xxx");
//设置可访问所有的https网站,可以把第一个参数改成具体网站证书的inputstream,比如getAssets().open("xx");
HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory(null, null, null);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
//设置网络超时
.readTimeout(7676, TimeUnit.MILLISECONDS)
.connectTimeout(7676,TimeUnit.MILLISECONDS)
//设置拦截器来打印网络请求的返回结果
.addInterceptor(logging)
.cookieJar(new JavaNetCookieJar(cookieHandler))
//开启okHttp缓存
.setCache(new Cache(httpCacheDirectory,10 * 1024 * 1024));
//对https网站的支持
.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager))
//通过设置拦截器的方式来addHeader
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request()
.newBuilder()
.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
.addHeader("Accept-Encoding", "gzip, deflate")
.addHeader("Connection", "keep-alive")
.addHeader("Accept", "*/*")
.addHeader("Cookie", "add cookies here")
.build();
return chain.proceed(request);
}
}))
.build();</span>
okhttp的官方不建议创建多个OkHttpClient对象 ,我们在项目中使用肯定要自己做封装,或者使用别人的封装框架。在后面我也会试着去自己封装一个全能的OkHttpUtils框架,这需要时间