官方介绍:http://square.github.io/okhttp/
http://square.github.io/retrofit/
引用:
AndroidStudio:
compile 'com.squareup.okhttp3:okhttp:3.6.0'
compile 'com.squareup.okio:okio:1.5.0'
Eclipse:
LastedOkHttpJar
okioJar
注意:最新版本的okhttp已经内置了okio包)
一:服务的初始化
官方不建议我们创建多个HttpClient,对系统资源消耗较大,如果实在有需求可以clone。关于一些常用的初始化设置如下:
client = new OkHttpClient();
OkHttpClient.Builder b = client.newBuilder();
b.connectTimeout(MAX_TIMEOUT, TimeUnit.SECONDS);
b.writeTimeout(MAX_TIMEOUT, TimeUnit.SECONDS);
b.readTimeout(MAX_TIMEOUT, TimeUnit.SECONDS);
b.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
client = b.build();
二:Get请求
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class Example{
public class GetExample {
OkHttpClient client = new OkHttpClient();
String run(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = client.newCall(request).execute()){
return response.body().string();
}
}
}
public static void test() throws IOException {
GetExample example = new GetExample();
String response = example.run("https://raw.github.com/square/okhttp/master/README.md");
System.out.println(response);
}
}
OkHttp的Response实现了lang.AutoCloseable接口(Java7新特性try-with-resources)
- 发送一个请求的步骤,首先构造一个Request对象,参数最起码有个url,当然你可以通过Request.Builder设置更多的参数比如:header、method等。
- 通过request的对象去构造得到一个Call对象,类似于将你的请求封装成了任务,既然是任务,就会有execute()和cancel()等方法。
- 我们这里是阻塞的方式去执行,当然也支持异步的方式,你也可以直接调用call.enqueue()。将call加入调度队列,然后等待任务执行完成,我们在Callback中即可得到结果Response。
三:Post请求
public class PostExample {
//可以定义多种多媒体传输类型
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
String run(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
//构造form表单数据请求方式
//FormBody.Builder body = new //FormBody.Builder();
//body.add(key, val);
Request request = new Request.Builder()
.url(url)
.tag(tag);
.post(body)//.post(body.build())
.build();
Response response = client.newCall(request).execute();
//或者采用异步方式请求
//请求加入调度
client.newCall(request).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();
}
});
return response.body().string();
}
}
public static void test() throws IOException {
PostExample example = new PostExample();
String json = "{}";
String response = example.run("http://www.roundsapp.com/post", json);
System.out.println(response);
}
注意:
- onResponse回调的参数是response,一般情况下,比如我们希望获得返回的字符串,可以通过response.body().string()获取;如果希望获得返回的二进制字节数组,则调用response.body().bytes();如果你想拿到返回的inputStream,则调用response.body().byteStream()。
看到这,你可能会奇怪,竟然还能拿到返回的inputStream,看到这个最起码能意识到一点,这里支持大文件下载,有inputStream我们就可以通过IO的方式写文件。不过也说明一个问题,这个onResponse执行的线程并不是UI线程。的确是的,如果你希望操作控件,还是需要使用handler等,我更喜欢用RxAndroid来封装请求和回调过程。或者可以结合Retrofit来封装网络请求更快捷。
@Override
public void onResponse(final Response response) throws IOException
{
final String res = response.body().string();
runOnUiThread(new Runnable()
{
@Override
public void run()
{
mTv.setText(res);
}
});
}
Observable<Result> obs = Observable.create(new Observable.OnSubscribe<Result>()
{
@Override
public void call(Subscriber<? super Result> subscriber)
{
try(Response response = http.syncExcute(url, p, tag))
{
if (response == null)
return;
if (response.isSuccessful())
{
String str = response.body().string();
L.i("HTTP", "RESPONSE>" + str+" url==="+url);
Result r = analyze(str, response.request().url().toString(), null);
subscriber.onNext(r);
} else
throw new Exception(" (" + response.code() + ")");
} catch (Exception e)
{
subscriber.onError(e);
}
}
});
obs = obs.subscribeOn(Schedulers.io());
obs = obs.observeOn(AndroidSchedulers.mainThread());
obs.subscribe(new Observer<Result>()
{
@Override
public void onCompleted()
{
}
@Override
public void onError(Throwable e)
{
if (callback == null)
return;
Result r = getErrorInfo(e, url.toString(), null);
callback.onHttpResp(r);
}
@Override
public void onNext(Result r)
{
if (callback == null)
return;
callback.onHttpResp(r);
}
});
//登录服务
public interface LoginService {
@FormUrlEncoded
@POST("login_user")
Call< LoginResult> doLogin(@Field("UserName") String userName, @Field("Password") String password);
}
/**
* 用户登录
*
* @param userName
* @param password
* @param callback
*/
public static void doLogin(String userName, String password, Callback<LoginResult> callback) {
ServiceManager.LoginService service = getRetrofit().create(ServiceManager.LoginService.class);
Call<LoginResult> result = service.doLogin(userName, CacheHelper.md5(password));
result.enqueue(callback);
}
public static synchronized Retrofit getRetrofit() {
return new Retrofit.Builder().baseUrl(ConstantParams.BASE_URL).client(getClientInstance())
.addConverterFactory(GsonConverterFactory.create()).build();
}
四.基于Http的文件上传
File file = new File(Environment.getExternalStorageDirectory(), "a.mp4");
RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addPart(Headers.of(
"Content-Disposition",
"form-data; name=\"username\""),
RequestBody.create(null, "william"))
.addPart(Headers.of(
"Content-Disposition",
"form-data; name=\"mFile\";filename =\"wjd.mp4\""), fileBody)
.build();
Request request = new Request.Builder().url("hostUrl/fileUpload")
.post(requestBody)
.build();
关于拼接上传文件的表单拼接模拟浏览器行为的方式。深度解析java http上传文件。
图片下载,文件下载;这两个一个是通过回调的Response拿到byte[]然后decode成图片;文件下载,就是拿到inputStream做写文件操作,这里就不赘述了。
注意:对于添加了retrofit之后想打印请求和返回数据的日志可以参考(评论也很重要,我项目最后采取的方法就是评论中的开源工具LoggingInterceptor)。
参考文档:http://blog.csdn.net/lmj623565791/article/details/47911083
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0106/2275.html
http://blog.csdn.net/lmj623565791/article/details/51304204#comments