okHttp是一个第三方的库被Square开发用来发送和接收接触的Http request 和response。它建立在Okio库上。Okio库试图通过共享内存池(shared memory pool)构建相比标准java I/O库,更有效的读写数据。它还是Retorfit的底层库提供更类型安全的消费REST-based API。
okHttp库事实上提供HttpUrlConnection的接口实现。底层HttpUrlConnection类可能是oKHttp库的底层实现。然而在oKHttp中的提供了一个分离的API,事发送以及接收网络请求更加容易。
OkHttp v2.4也提供了一个内部管理URL的升级方法,替代java.net.URL
,java.net.URI
,或者android.net.Uri
类,它提供了一个新的HttpUrl
类,提供更加方便的方法获取Http端口,URL解析,和处理URL字符串。
SetUp
确保在AndroidManifest.xml
文件中打开了使用网络权限:
<uses-permission android:name="android.permission.INTERNET"/>
将下列行添加到你的app/build.gradle
文件中:
compile 'com.squareup.okhttp3:okhttp:3.3.0'
Note:如果将okHttp升级,导入也需要修改为:
import com.squareup.okhttp.XXXX to import okhttp3.XXXX
Note:如果你打算在OkHttp3中使用Picasso,确保添加基础下载。这个变化是必须的直到下个版本的Picasso
dependencies{
compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.0.2'
}
Sending and Receiving Network Requests
首先 我们初始化okHttpclient 并且建立一个 Request实例
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build()
如果需要添加其他的查询参数,这个okHttp库提供HttpUrl
类可以方便的构造URL:
HttpUrl.Builder urlBuilder = HttpUrl.parse("https://ajax.googleapis.com/ajax/services/search/images").newBuilder();
urlBuilder.addQueryParameter("v", "1.0");
urlBuilder.addQueryParameter("q", "android");
urlBuilder.addQueryParameter("rsz", "8");
Sring url = urlBuilder.build().toString();
Request request = new Request.Builder()
.url(url)
.build();
如果有任何查询效验参数,request可以添加效验头部:
Request request = new Request.Builder()
.header("Authorization", "token abcd")
.url("https://api.github.com/users/codepath")
.build();
Http Post Json
public static final MediaType JSON = MediaType.parse("application/json; charset = utf-8")
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException{
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
if(response.isSuccessful())
{
return response.body().string();
}else{
throw new IOException("Unexpected code " + response);
}
}
Htttp Post 提交键值对
使用FormEncodingBuilder 来构建和HTML <form>标签相同效果的请求体,键值对将使用一种HTML兼容形式的URL编码来进行编码。
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException{
RequestBody formBody = new FormEncodingBuilder()
.add("platform", "android")
.add("name", "bug")
.add("subject", "XXXXXXXXX")
.build();
Request request = new Request.Builder()
.url(url)
.post(formBody)
.build();
Response response = client.newCall(request).execute();
if (response,isSuccessful()){
return response.body().string();
}else{
throw new IOException("Unexpected code" + response)
}
}
Post 方式提交流
以流的方式POST提交请求体,请求体的内容由i流写入产成。
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
RequestBody requestBody = new RequsetBody(){
@Override
public MediaType contentType(){
return MEDIA_TYPE_MARKDOWN;
}
@Override
public void writeTo(BufferedSink sink) throws IOException{
sink.writeUtf8("Numbers\n");
sink.writeUtf8("------------\n");
for (int i = 2; i <=997; i++)
{
sink.writeUtf8(String.format("* %s = %s\n", i, factor(i)));
}
}
private String factor(int n)
{
for(int i = 2 ; i< n; i++)
{
int x = n / i;
if(x * i == n)
return factor(x) + " x " + i;
}
return Integer.toString(n);
}
};
Request request = new Request.Builder()
.url("[https://api.github.com/markdown/raw](https://api.github.com/markdown/raw)")
.post(requestBody)
.build();
}
Post 方式提交文件
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
private void run() throws Exception{
File file = new File("README.md");
Request request = new Request.Builder()
.url("[https://api.github.com/markdown/raw](https://api.github.com/markdown/raw)")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
.build();
}
Synchronous Network Calls
我们创建Call实例并且分发网络同步请求:
Response response = client.newCall(requset).execute();
由于Android不允许主线程中进行网络调用,如果你在分离的线程或者后台服务,你可以使用synchronous调用。你也可以使用AsyncTask 用于轻量级的网络调用。
Asynchronous Network Calls
我们也可以创建一个异步网络调用,通过创建一个Call
对象。通过使用enqueue()方法并且传入一个匿名Callback对象,并且实现onFailure()和onResponse()方法
client.newCall(request).enqueue(new Callback(){
@Override
public void onFailure(Call call,IOException e)
{
e.printStackTrace();
}
@Override
public void onResponse(Call call,final Response response) throws IOException
{
if(!response.isSuccessful()){
throw new IOException("Unexpected code " + response);
}
}
})
OkHttp 通常创建一个新的工作线程分发网络请求,并且使用相同的线程去处理响应。OkHttp建立的目的是作为一个Java库,并不处理Android框架中的限制(view 只允许在主线程中更新)。如果你需要更新任何view,你需要runOnUiThread()
方法,并且将结果返回至主线程。
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(Call call, final Response response) throws IOException {
final String responseData = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
TextView myTextView = (TextView)findViewById(R.id.myTextView);
myTextView.setText(responseData);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
});
Processing Network Response
假设Request没有被取消并且没有connect问题,并且 onResponse()方法将被调用。他传递一个 Response 实例,并且可以被用来查看状态码,响应体,以及任何相应头将会被返回。调用 isSuccessful() 对应实例码相应状态码 2XX (i.e 200, 201)
if (!response.isSuccessful()){
throw new IOException("Unexcepted code" + response);
}
响应头被作为一个列表返回:
Headers responseHeaders = response.header();
for (int i = 0; i < responseHeaders.size(); i++)
{
Log.d("DEBUG", responseHeaders.name(i) + ":" + responseHeaders.value(i));
}
我们也可以获得响应数据,通过调用 response.body()并且调用 string() 方法去读取整个playload,注意 response.body()只可以被调用一次,并且应该在后台线程中调用。
Log.d("DEBUG", response.body().string());
Processing JSON data
我们调用Github API ,将会返回JSON 数据:
Request request = new Request.Builder()
.url("https://api.github.com/users/codepath")
.build();
我们可以解析JOSN 数据 通过JSONobject 或者 JSONArray 类,这取决于响应数据类型:
client.newCall(request).enqueue(new Callback(){
@Override
public void onResponse(Call call, final Response response) throws IOException{
try{
String responseData = response.body().string();
JSONObject json = new JSONObject(responseData);
final String owner = json.getString("name");
}catch (JSONException e )
{
}
}
});
Processing JSON data with Gson
注意 sting() 方法作用在响应体将会将所有的数据加载到内存中。为了更加合理的使用内存,推荐响应进程通过 使用charStream()
代替
为了使用Gson库,我们首先要声明类匹配JSON 响应:
static class GitUser{
String name;
String url;
int id;
}
我们可以使用使用Gson解析器,将数据转换到java模型中:
final Gson gson = new Gson();
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(Call call, final Response response) throws IOException {
GitUser user = gson.fromJson(response.body().charStream(), GitUser.class);
}
}
Caching Network Responses
我们可以创建OkHttpClient并且配置cache缓存:
int cacheSize = 10 * 1024 * 1024 ; // 10 Mib
Cache cache = new Cache(getApplication().getCacheDir(),cacheSize);
OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();
我们可以控制是否取回缓存相应通过在request上设置cacheControl属性。如过我们希望获取缓存中的响应数据,我们可以向下面一样配置Request实例
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.cacheControl(new CacheControl.Builder().onlyIfCached().build())
.build();
我们可以设置request请求响应response 使用noCache()
.cacheControl(new CacheControl.Builder().noCache().build())
我们也可以标明响应缓存的最大生存周期
.cacheControl(new CacheControl.Builder().maxStale(365,TimeUnit.DAYS).build())
为了取回cache相应,我们可以简单的在响应实例上调用cacheResponse()
Call call = client.newCall(request);
call.enqueue(new Callback(){
@Override
public void onFailure(Call call, IOException e){
}
@Override
public void onResponse(Call call, final Response response) throws IOException
{
final Response text = response.cacheResponse();
if(text != null){
Log.d("here", text.toString());
}
}
});