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

Android开发---OkHttp简单封装

2017-11-09 20:42 465 查看
今天看到一篇关于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()进行


具体实现就不细说了,直接上代码如下:

[html] view
plain copy

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

}

}

其中的 BaseCallBack回调机制封装如下:

[java] view
plain copy

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类,根据请求数据的功能的不同,还需要对此进行封装,集成自己需要的方法实现;

一、进行一般的数据加载请求,可直接调用如下:

模拟用户登录:

[java] view
plain copy

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>类:

[java] view
plain copy

//添加对请求时对话框的处理

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) {

}

其实这个类就是对BaseCallBack再次继承实现;

二、下载文件,并显示进度条对话框的请求操作:

下载一张图片:

[java] view
plain copy

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>类如下:

[java] view
plain copy

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);

}

}

三、最后说一下使用okhttp的配置:

在Android Studio 中,直接在build.gradle文件里配置 :compile 'com.squareup.okhttp3:okhttp:3.4.1'
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: