今天看到一篇关于okhttp简单封装的博文,特借鉴一下留作备用
OkHttp 分为同步和异步请求;请求方式常用的有 get和post两种方式,封装请求的大致步骤为:
1、首先 创建 一个mOkHttpClient = new OkHttpClient()对象;
2、构建Request请求对象(根据get和post不同的请求方式分别创建);
3、如果是 post请求还需要 构建 请求参数 Params,RequestBody requestBody = buildFormData(params); builder.post(requestBody).build;;
4、进行网络异步请求 mOkHttpClient.newCall(request).enqueue(new Callback() {} ),如果是同步请求,则改为 Response response = mOkHttpClient.newCall(request).execute()进行 ;
具体实现就不细说了,直接上代码如下:
- public class OkHttpManager {
- private static OkHttpManager mOkHttpManager;
- private OkHttpClient mOkHttpClient;
- private Gson mGson;
- private Handler handler;
- private OkHttpManager() {
- mOkHttpClient = new OkHttpClient();
- mOkHttpClient.newBuilder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS)
- .writeTimeout(10, TimeUnit.SECONDS);
- mGson = new Gson();
- handler = new Handler(Looper.getMainLooper());
- }
- //创建 单例模式(OkHttp官方建议如此操作)
- public static OkHttpManager getInstance() {
- if (mOkHttpManager == null) {
- mOkHttpManager = new OkHttpManager();
- }
- return mOkHttpManager;
- }
- /***********************
- * 对外公布的可调方法
- ************************/
- public void getRequest(String url, final BaseCallBack callBack) {
- Request request = buildRequest(url, null, HttpMethodType.GET);
- doRequest(request, callBack);
- }
- public void postRequest(String url, final BaseCallBack callBack, Map<String, String> params) {
- Request request = buildRequest(url, params, HttpMethodType.POST);
- doRequest(request, callBack);
- }
- public void postUploadSingleImage(String url, final BaseCallBack callback, File file, String fileKey, Map<String, String> params) {
- Param[] paramsArr = fromMapToParams(params);
- try {
- postAsyn(url, callback, file, fileKey, paramsArr);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public void postUploadMoreImages(String url, final BaseCallBack callback, File[] files, String[] fileKeys, Map<String, String> params) {
- Param[] paramsArr = fromMapToParams(params);
- try {
- postAsyn(url, callback, files, fileKeys, paramsArr);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- /***********************
- * 对内方法
- ************************/
- //单个文件上传请求 不带参数
- private void postAsyn(String url, BaseCallBack callback, File file, String fileKey) throws IOException {
- Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, null);
- doRequest(request, callback);
- }
- //单个文件上传请求 带参数
- private void postAsyn(String url, BaseCallBack callback, File file, String fileKey, Param... params) throws IOException {
- Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, params);
- doRequest(request, callback);
- }
- //多个文件上传请求 带参数
- private void postAsyn(String url, BaseCallBack callback, File[] files, String[] fileKeys, Param... params) throws IOException {
- Request request = buildMultipartFormRequest(url, files, fileKeys, params);
- doRequest(request, callback);
- }
- //异步下载文件
- public void asynDownloadFile(final String url, final String destFileDir, final BaseCallBack callBack) {
- final Request request = buildRequest(url, null, HttpMethodType.GET);
- callBack.OnRequestBefore(request); //提示加载框
- mOkHttpClient.newCall(request).enqueue(new Callback() {
- @Override
- public void onFailure(Call call, IOException e) {
- callBack.onFailure(call, e);
- }
- @Override
- public void onResponse(Call call, Response response) throws IOException {
- // callBack.onResponse(response);
- InputStream is = null;
- byte[] buf = new byte[1024*2];
- final long fileLength = response.body().contentLength();
- int len = 0;
- long readLength = 0;
- FileOutputStream fos = null;
- try {
- is = response.body().byteStream();
- File file = new File(destFileDir, getFileName(url));
- fos = new FileOutputStream(file);
- while ((len = is.read(buf)) != -1) {
- fos.write(buf, 0, len);
- readLength += len;
- int curProgress = (int) (((float) readLength / fileLength) * 100);
- Log.e("lgz", "onResponse: >>>>>>>>>>>>>" + curProgress + ", readLength = " + readLength + ", fileLength = " + fileLength);
- callBack.inProgress(curProgress, fileLength, 0);
- }
- fos.flush();
- //如果下载文件成功,第一个参数为文件的绝对路径
- callBackSuccess(callBack, call, response, file.getAbsolutePath());
- } catch (IOException e) {
- callBackError(callBack, call, response.code());
- } finally {
- try {
- if (is != null)
- is.close();
- } catch (IOException e) {
- }
- try {
- if (fos != null)
- fos.close();
- } catch (IOException e) {
- }
- }
- }
- });
- }
- //构造上传图片 Request
- private Request buildMultipartFormRequest(String url, File[] files, String[] fileKeys, Param[] params) {
- params = validateParam(params);
- MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
- for (Param param : params) {
- builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + param.key + "\""),
- RequestBody.create(MediaType.parse("image/png"), param.value));
- }
- if (files != null) {
- RequestBody fileBody = null;
- for (int i = 0; i < files.length; i++) {
- File file = files[i];
- String fileName = file.getName();
- fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
- //TODO 根据文件名设置contentType
- builder.addPart(Headers.of("Content-Disposition",
- "form-data; name=\"" + fileKeys[i] + "\"; filename=\"" + fileName + "\""),
- fileBody);
- }
- }
- RequestBody requestBody = builder.build();
- return new Request.Builder()
- .url(url)
- .post(requestBody)
- .build();
- }
- //Activity页面所有的请求以Activity对象作为tag,可以在onDestory()里面统一取消,this
- public void cancelTag(Object tag) {
- for (Call call : mOkHttpClient.dispatcher().queuedCalls()) {
- if (tag.equals(call.request().tag())) {
- call.cancel();
- }
- }
- for (Call call : mOkHttpClient.dispatcher().runningCalls()) {
- if (tag.equals(call.request().tag())) {
- call.cancel();
- }
- }
- }
- private String guessMimeType(String path) {
- FileNameMap fileNameMap = URLConnection.getFileNameMap();
- String contentTypeFor = fileNameMap.getContentTypeFor(path);
- if (contentTypeFor == null) {
- contentTypeFor = "application/octet-stream";
- }
- return contentTypeFor;
- }
- private String getFileName(String path) {
- int separatorIndex = path.lastIndexOf("/");
- return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1, path.length());
- }
- private Param[] fromMapToParams(Map<String, String> params) {
- if (params == null)
- return new Param[0];
- int size = params.size();
- Param[] res = new Param[size];
- Set<Map.Entry<String, String>> entries = params.entrySet();
- int i = 0;
- for (Map.Entry<String, String> entry : entries) {
- res[i++] = new Param(entry.getKey(), entry.getValue());
- }
- return res;
- }
- //去进行网络 异步 请求
- private void doRequest(Request request, final BaseCallBack callBack) {
- callBack.OnRequestBefore(request);
- mOkHttpClient.newCall(request).enqueue(new Callback() {
- @Override
- public void onFailure(Call call, IOException e) {
- callBack.onFailure(call, e);
- }
- @Override
- public void onResponse(Call call, Response response) throws IOException {
- callBack.onResponse(response);
- String result = response.body().string();
- if (response.isSuccessful()) {
- if (callBack.mType == String.class) {
- // callBack.onSuccess(call, response, result);
- callBackSuccess(callBack, call, response, result);
- } else {
- try {
- Object object = mGson.fromJson(result, callBack.mType);//自动转化为 泛型对象
- // callBack.onSuccess(call, response, object);
- callBackSuccess(callBack, call, response, object);
- } catch (JsonParseException e) {
- //json解析错误时调用
- callBack.onEror(call, response.code(), e);
- }
- }
- } else {
- callBack.onEror(call, response.code(), null);
- }
- }
- });
- }
- //创建 Request对象
- private Request buildRequest(String url, Map<String, String> params, HttpMethodType methodType) {
- Request.Builder builder = new Request.Builder();
- builder.url(url);
- if (methodType == HttpMethodType.GET) {
- builder.get();
- } else if (methodType == HttpMethodType.POST) {
- RequestBody requestBody = buildFormData(params);
- builder.post(requestBody);
- }
- return builder.build();
- }
- //构建请求所需的参数表单
- private RequestBody buildFormData(Map<String, String> params) {
- FormBody.Builder builder = new FormBody.Builder();
- builder.add("platform", "android");
- builder.add("version", "1.0");
- builder.add("key", "123456");
- if (params != null) {
- for (Map.Entry<String, String> entry : params.entrySet()) {
- builder.add(entry.getKey(), entry.getValue());
- }
- }
- return builder.build();
- }
- private void callBackSuccess(final BaseCallBack callBack, final Call call, final Response response, final Object object) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- callBack.onSuccess(call, response, object);
- }
- });
- }
- private void callBackError(final BaseCallBack callBack, final Call call, final int code) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- callBack.onEror(call, code, null);
- }
- });
- }
- private Param[] validateParam(Param[] params) {
- if (params == null)
- return new Param[0];
- else
- return params;
- }
- public static class Param {
- public Param() {
- }
- public Param(String key, String value) {
- this.key = key;
- this.value = value;
- }
- String key;
- String value;
- }
- enum HttpMethodType {
- GET, POST
- }
- }
- public abstract class BaseCallBack<T> {
- public Type mType;
- static Type getSuperclassTypeParameter(Class<?> subclass) {
- Type superclass = subclass.getGenericSuperclass();
- if (superclass instanceof Class) {
- throw new RuntimeException("Missing type parameter.");
- }
- ParameterizedType parameterized = (ParameterizedType) superclass;
- return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
- }
- public BaseCallBack() {
- mType = getSuperclassTypeParameter(getClass());
- }
- protected abstract void OnRequestBefore(Request request);
- protected abstract void onFailure(Call call, IOException e);
- protected abstract void onSuccess(Call call, Response response, T t);
- protected abstract void onResponse(Response response);
- protected abstract void onEror(Call call, int statusCode, Exception e);
- protected abstract void inProgress(int progress, long total , int id);
- }
上面这个类OkHttpManager 是我根据网络上各家资源学习封装好的,copy进代码可以直接使用,并且根据okhttp3.0以后的版本,对之前的一下请求参数设置进行了最新的修改,具体如下:
1、设置请求超时参数;
okhttp3.0以前的版本是这样设置的
new OkHttpClient();
mHttpClient.setConnectTimeout(10, TimeUnit.SECONDS);
mHttpClient.setReadTimeout(10,TimeUnit.SECONDS);
mHttpClient.setWriteTimeout(30,TimeUnit.SECONDS);
之后的版本是这样设置的:
new OkHttpClient.Builder()
.readTimeout(READ_TIMEOUT,TimeUnit.SECONDS)//设置读取超时时间
.writeTimeout(WRITE_TIMEOUT,TimeUnit.SECONDS)//设置写的超时时间
.connectTimeout(CONNECT_TIMEOUT,TimeUnit.SECONDS)//设置连接超时时间
2、post方式请求时,构建表单对象参数;
okhttp3.0以前的版本是这样构建的:new FormEncodingBuilder()对象,然后向里面add (key,value)参数;
之后的版本更改为:FormBody body = new FormBody.Builder(),.add(key, value);即是FormEncodingBuilder已被FormBody取代;
至于BaseCallBack类,根据请求数据的功能的不同,还需要对此进行封装,集成自己需要的方法实现;
一、进行一般的数据加载请求,可直接调用如下:
模拟用户登录:
- Map<String, String> params = new HashMap<String, String>();
- params.put("Mobile", username.getText().toString());
- params.put("PassWord", password.getText().toString());
- OkHttpManager.getInstance().postRequest(Constants.LOGIN_URL, new LoadCallBack<String>(getActivity()) {
- @Override
- protected void onSuccess(Call call, Response response, String s) {
- Log.e("lgz", "onSuccess = " + s);
- Toast.makeText(getActivity(), "登录成功!", Toast.LENGTH_LONG).show();
- }
- @Override
- protected void onEror(Call call, int statusCode, Exception e) {
- Log.e("lgz", "Exception = " + e.toString());
- }
- }
- , params);
上面登录请求中 就用到了自己根据需要再次封装的Callback类的继承实现,LoadCallBack<T>类:
- //添加对请求时对话框的处理
- public abstract class LoadCallBack<T> extends BaseCallBack<T> {
- private Context context;
- private SpotsDialog spotsDialog;
- public LoadCallBack(Context context) {
- this.context = context;
- spotsDialog = new SpotsDialog(context);
- }
- private void showDialog() {
- spotsDialog.show();
- }
- private void hideDialog() {
- if (spotsDialog != null) {
- spotsDialog.dismiss();
- }
- }
- public void setMsg(String str) {
- spotsDialog.setMessage(str);
- }
- public void setMsg(int resId) {
- spotsDialog.setMessage(context.getString(resId));
- }
- @Override
- protected void OnRequestBefore(Request request) {
- showDialog();
- }
- @Override
- protected void onFailure(Call call, IOException e) {
- hideDialog();
- }
- @Override
- protected void onResponse(Response response) {
- hideDialog();
- }
- @Override
- protected void inProgress(int progress, long total, int id) {
- }
二、下载文件,并显示进度条对话框的请求操作:
下载一张图片:
- OkHttpManager.getInstance().asynDownloadFile("http://www.7mlzg.com/uploads/bwf_1477419976.jpg", FILE_PATH, new FileCallBack<String>(getActivity()) {
- @Override
- protected void onResponse(Response response) {
- }
- @Override
- protected void onSuccess(Call call, Response response, String s) {
- super.onSuccess(call, response, s);
- Log.e("lgz", "status = : " + s);
- Toast.makeText(getActivity(), "下载成功", Toast.LENGTH_LONG).show();
- Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
- Uri uri = Uri.fromFile(new File(s));//广播通知系统图集更新
- intent.setData(uri);
- getActivity().sendBroadcast(intent);
- }
- });
上面下载图片中,就用到了自己根据需要再次继承Callback类封装得到的FileCallBack<T>类如下:
- public abstract class FileCallBack<T> extends BaseCallBack<T> {
- private Context mContext;
- private ProgressDialog mProgressDialog;
- public FileCallBack(Context context) {
- mContext = context;
- initDialog();
- }
- private void initDialog(){
- mProgressDialog = new ProgressDialog(mContext);
- mProgressDialog.setTitle("下载中...");
- mProgressDialog.setCanceledOnTouchOutside(true);
- mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- mProgressDialog.setMax(100);
- }
- private void hideDialog() {
- if (mProgressDialog != null) {
- mProgressDialog.dismiss();
- }
- }
- @Override
- protected void OnRequestBefore(Request request) {
- mProgressDialog.show();
- }
- @Override
- protected void onFailure(Call call, IOException e) {
- hideDialog();
- }
- @Override
- protected void onSuccess(Call call, Response response, T t) {
- Log.e("lgz", "onSuccess: >>>>>>>>>>>>>");
- hideDialog();
- }
- @Override
- protected void onEror(Call call, int statusCode, Exception e) {
- hideDialog();
- }
- @Override
- protected void inProgress(int progress, long total, int id) {
- Log.e("lgz", "inProgress: >>>>>>>>>>>>>"+progress);
- mProgressDialog.setProgress(progress);
- }
- }
在Android Studio 中,直接在build.gradle文件里配置 :compile 'com.squareup.okhttp3:okhttp:3.4.1'