您的位置:首页 > 理论基础 > 计算机网络

OKHttp 使用

2015-09-10 11:30 1246 查看
Android网络请求框架很多,为什么我选择的是Okhttp?

也许是不经意之间听到Android4.4的源码里面都用了她,又或者是她支持Google开发的SPDY协议,

又或者她来自鼎鼎大名的Square?

其实我也不知道,就想试一下;

在使用过程出现很多问题,相比于那些成熟的网络框架, 体现出来的是OkHttp相当于HttpClient和HttpURLConnection这种底层一点的,而其余的所有网络请求框架基本都是对HttpClient和HttpURLConnection封装,所以很多框架都在网络请求上可以用她来作为底层,Volley可以用她再来作为底层的网络请求,Fresco也可以,在Fresco的一个Demo中,Fresco+OkHttp速度最快,不知道是不是偶然,我自己测试是如此,等等其他很多。

在当前项目中使用的是这个,所以为了方便处理,做了一些封装,有自己的封装也有参考网上资料的,整合力一下。

先看几个请求方式和请求结果 gif是按照顺序来操作



文件上传的log细节



文件下载的log细节



先看看对OkHttp使用的封装

public class OkHttpUtil {
public static final OkHttpClient mOkHttpClient = new OkHttpClient();

static {
mOkHttpClient.setConnectTimeout(30, TimeUnit.SECONDS);
mOkHttpClient.setWriteTimeout(20, TimeUnit.SECONDS);
mOkHttpClient.setReadTimeout(30, TimeUnit.SECONDS);
}

//自定义接口 目的是在调用的地方可以直接更新UI
public interface MyCallBack {
void onFailure(Request request, IOException e);
void onResponse(String json);
}

//配置OKHttp的Cookie策略,有些地方需要做一些cookie相关的操作
public static void setCookie(CookieManager cookieManager) {
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
mOkHttpClient.setCookieHandler(cookieManager);
}

public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

/**
* 异步回调方式 请求  自定义回调接口  结果运行在UI线程
*/
public static void postData2Server(final Activity activity, Request request, final MyCallBack myCallBack) {
final String url = request.urlString();
try {
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(final Request request, final IOException e) {
if (activity == null) {
return;
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
myCallBack.onFailure(request, e);
}
});
}

@Override
public void onResponse(Response response) throws IOException {
final String json = response.body().string();
if (activity == null) {
return;
}
//直接更新UI
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
myCallBack.onResponse(json);
}
});
}
});
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* Daemon
* -----------------一开始没有发现好的封装对于上传和下载
* 就用的下面的两个方法  后面发现在OKHttp的sample中有相关的例子 然后网上也有人写 就借鉴过来了
* --------------------所以这两个就没用了-----------------------------------------------
*/

/**
* 下载显示进度的方法1
*
* @param url
*/
public static void dowloadProgress(Context context, final String url) {

Request request = new Request.Builder().url(url)
.build();
new AsyncDownloader(context).execute(request);

}

private static class AsyncDownloader extends AsyncTask<Request, Long, Boolean> {

private Context context;

public AsyncDownloader(Context context) {
this.context = context;
}

@Override
protected Boolean doInBackground(Request... params) {

Call call = mOkHttpClient.newCall(params[0]);
try {
Response response = call.execute();
if (response.code() == 200) {
InputStream inputStream = null;
OutputStream output = null;
try {
inputStream = response.body().byteStream();
File file = new File(context.getCacheDir(), "download.liubo");
output = new FileOutputStream(file);

byte[] buff = new byte[1024 * 4];
long downloaded = 0;
long target = response.body().contentLength();

publishProgress(0L, target);
while (true) {
int readed = inputStream.read(buff);
if (readed == -1) {
break;
}
//write buff
output.write(buff, 0, readed);

downloaded += readed;
publishProgress(downloaded, target);

if (isCancelled()) {
return false;
}
}
output.flush();

return downloaded == target;
} catch (IOException ignore) {
return false;
} finally {
if (inputStream != null) {
inputStream.close();
}
if (output != null) {
output.close();
}
}
} else {
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
}

@Override
protected void onProgressUpdate(Long... values) {

LogUtils.e(String.format("%d / %d", values[0], values[1]));

}

@Override
protected void onPostExecute(Boolean result) {
//下载完成后
}
}

/**
* 上传文件方法1   进度显示
*/
public static RequestBody createCustomRequestBody(final MediaType contentType, final File file) {
return new RequestBody() {
@Override
public MediaType contentType() {
return contentType;
}

@Override
public long contentLength() {
return file.length();
}

@Override
public void writeTo(BufferedSink sink) throws IOException {
Source source = null;
try {
source = Okio.source(file);
//sink.writeAll(source);
Buffer buf = new Buffer();
Long remaining = contentLength();
for (long readCount; (readCount = source.read(buf, 2048)) != -1; ) {
sink.write(buf, readCount);
LogUtils.e("source size: " + contentLength() + " remaining bytes: " + (remaining -= readCount));
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
}
}


这里是一些OKHttp使用中的一些操作

//如果json body这么构建

RequestBody body = RequestBody.create(JSON, json);
如果获取sessionID
Map<String, List<String>> map = new HashMap<String, List<String>>();
//获取cookie 然后打印  绑定
try {
BaseRequest.Cookies = response.headers().get("Set-Cookie");
Logger.getLogger().e(response.headers().toString());
map = mOkHttpClient.getCookieHandler().get(URI.create(url),   response.headers().toMultimap());
for (String key : map.keySet()) {
syso(key + " --  " + map.get(key).toString());
if ("Cookie".equals(key)) {
sessionId = map.get(key).get(0);
}
}
} catch (IOException e) {
e.printStackTrace();
}
在请求的时候带上cookie  在Request构建的时候加上头部就行
.addHeader("cookie", sessionId)


其实很简单 只是新增一个接口 让其可以UI更新

其实大家看到了 上面有两个方法一个是 下载的进度显示和一个上传的进度显示 这是以前使用的 也能达到效果

后面有一天在微博看到相关的封装 对已上传和下载的进度显示 就集成进来项目中



红线部分是对于上传和下载的进度显示的类和接口

这里的话 去看这个吧 我是从这个看到的写的挺好的

http://blog.csdn.net/sbsujjbcy/article/details/48194701

或者这个也行 官方的demo

https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/com/squareup/okhttp/recipes/Progress.java

然后看看在整个项目中的一些设置

有BaseActivity的ondestyoy中的 请求取消

public class BaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected void onDestroy() {
super.onDestroy();
OkHttpUtil.mOkHttpClient.cancel(this);
}
}

//MyApplication的oncreate中的okhttp的cookie的设置

public class MyApplication extends Application {
private static Context mInstance;
@Override
public void onCreate() {
super.onCreate();
mInstance = getBaseContext();
//cookie策略 让OkHttp接受所有的cookie
CookieManager cookieManager = new CookieManager();
OkHttpUtil.setCookie(cookieManager);
}

public static Context getContext() {
return mInstance;
}
}


实际运用

/**

* 数据获取Get请求

*/

Request request
= new Request.Builder().url("http://www.baidu.com")
.tag(this)
.build();

OkHttpUtil.postData2Server(this, request, new OkHttpUtil.MyCallBack() {
@Override
public void onFailure(Request request, IOException e) {

}

@Override
public void onResponse(String json) {
showData(json);

}
});


/**

* 数据上传 Post请求

*/

RequestBody requestBody = new FormEncodingBuilder()
.add("action_flag", "user_login")
.add("mobile_phone", "18566757335")
.add("user_password", "liubo123")
.build();

Request request = new Request.Builder()
.post(requestBody)
.url("登陆接口")
.tag(this)
.build();

OkHttpUtil.postData2Server(this, request, new OkHttpUtil.MyCallBack() {
@Override
public void onFailure(Request request, IOException e) {

}

@Override
public void onResponse(String json) {
showData(json);
}
});


/**

* 图片下载

*/

UIProgressResponseListener uiProgressResponseListener = new UIProgressResponseListener() {
@Override
public void onUIResponseProgress(long bytesRead, long contentLength, boolean done) {
LogUtils.e("bytesRead:" + bytesRead);
LogUtils.e("contentLength:" + contentLength);
LogUtils.e("done:" + done);

if (contentLength != -1) {
// LogUtils.e( (100 * bytesRead) / contentLength + "% done");
}
LogUtils.e("================================");
//ui层回调
tvshow.setText("下载进度 " + ((100 * bytesRead) / contentLength) + "%");
}
};

//构造请求
final Request request1 = new Request.Builder()
.url("网上资源接口")
.build();

//包装Response使其支持进度回调
ProgressHelper.addProgressResponseListener(OkHttpUtil.mOkHttpClient, uiProgressResponseListener)
.newCall(request1)
.enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
Log.e("TAG", "error ", e);
}

@Override
public void onResponse(Response response) throws IOException {
InputStream inputStream = null;
OutputStream output = null;
try {
inputStream = response.body().byteStream();
file = new File(getCacheDir(), "download.jpg");
output = new FileOutputStream(file);
byte[] buff = new byte[1024 * 4];
while (true) {
int readed = inputStream.read(buff);
if (readed == -1) {
break;
}
//write buff
output.write(buff, 0, readed);
}
output.flush();
} catch (IOException e) {
file = null;
e.printStackTrace();
} finally {
if (inputStream != null) {
inputStream.close();
}
if (output != null) {
output.close();
}
}
}
}
);


/**

* 图文上传

*/

private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
if (file == null) {
ToastUtil.showToast("先下载图片在试着上传吧");
return;
}
tvshow.setText("");

MultipartBuilder mb = new MultipartBuilder();
mb.type(MultipartBuilder.FORM);
mb.addFormDataPart("user_id", "74");
mb.addFormDataPart("user_head", "user_head.jpg", RequestBody.create(MEDIA_TYPE_PNG, file));
RequestBody requestBody = mb.build();

UIProgressRequestListener progressListener = new UIProgressRequestListener() {

@Override
public void onUIRequestProgress(long bytesWrite, long contentLength, boolean done) {
Log.e("TAG", "bytesWrite:" + bytesWrite);
Log.e("TAG", "contentLength" + contentLength);
Log.e("TAG", (100 * bytesWrite) / contentLength + " % done ");
Log.e("TAG", "done:" + done);
Log.e("TAG", "================================");

tvshow.setText("上传进度 " + ((100 * bytesWrite) / contentLength) + "%");

}
};

Request request = new Request.Builder()
.url("上传的接口")
.post(new ProgressRequestBody(requestBody, progressListener))
.tag(this)
.build();

OkHttpUtil.postData2Server(this, request, new OkHttpUtil.MyCallBack() {
@Override
public void onFailure(Request request, IOException e) {

}

@Override
public void onResponse(String json) {

}
});


//数据的显示

private void showData(String json) {
tvshow.setText("");
tvshow.setText(json);
}


以上就是四个例子的使用方法

关于Json的上传和cookie的使用在OkHttpUtil的注释里面有介绍

因为我写demo的效果都是用的公司的接口 所以上面把接口都给取消 需要的自己把接口加上去才能使用

demo上传到http://download.csdn.net/detail/liubo080852/9094387

有需要的可以下载哈
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息