我们来看一个正常的okhttp请求:
OkHttpClient client = new OkHttpClient(); RequestBody body = new FormBody.Builder() .add("bookid",String.valueOf(mBook.bookid)) .add("bookName",mBookNameEdit.getText().toString()).build(); final Request request = new Request.Builder() .url("http://139.199.89.89/api/v1/books") .post(body).build(); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.d(TAG,"<<<<e="+e); } @Override public void onResponse(Call call, Response response) throws IOException { if(response.isSuccessful()) { String d = response.body().string(); Log.d(TAG,"<<<<d="+d); } } });
这个有什么问题呢,第一个这个callback肯定是子线程,我们在onResponse里不能去更新UI,
还有如果对于每一个请求都要写这么一段,显得很繁琐,不够简洁,如果想往url加入一些公共参数,
显然这个也是不能实现的
那么下面我们就来封装一下这个接口:我们首先需要继承这个callback
public abstract class OkHttpResJsonHandler extends OkHttpCallback<JSONObject> { @Override protected JSONObject parseResponse(Response response) throws Throwable { return responseToJson(response); } }
private OkHttpResJsonHandler mSendListener = new OkHttpResJsonHandler() { @Override protected boolean isPostMainThread() { return isBackMainThread(); } @Override public void onSuccess(Call call, int statusCode, Headers headers, JSONObject response) { if (null != response) { String status = response.optString(STATUS); String statusMessage = response.optString(MESSAGE); if (TextUtils.isEmpty(statusMessage)) { setStatus(status, ApiStatus.getStatusMessage(status)); } else { setStatus(status, statusMessage); } if (isSuccess()) { try { dismissLoading(); onParse(response); if (null != mApiListener) { mApiListener.success(ApiUtil.this); } } catch (Exception e) { e.printStackTrace(); failure(API_STATUS_PARSE_ERROR, mContext.getString(R.string.parse_error)); } } else { if ("failed".equals(getStatus())) { // 兼容data里含有message字段的api 优先级最高 JSONObject data = response.optJSONObject(DATA); if (data != null) { String message = data.optString(MESSAGE); if (!TextUtils.isEmpty(message)) { failure(status, message); } else { message = response.optString(MESSAGE); if (!TextUtils.isEmpty(message)) { failure(status, message); } else { failure(status, getStatusMessage()); } } } } } } else { failure(API_STATUS_PARSE_ERROR, mContext.getString(R.string.parse_error)); } } @Override public void onFailure(Call call, int code, Headers headers, int error, Throwable t) { if (code == 403) { failure(API_STATUS_REJECT_ERROR, "系统繁忙,请稍后再试"); } else if (error == OkHttpCallback.RESPONSE_ERROR_SERVER) { failure(API_STATUS_NET_ERROR, "服务器处理错误"); } else if (error == OkHttpCallback.RESPONSE_ERROR_TIMEOUT) { failure(API_STATUS_TIMEOUT, "服务器处理错误"); } else if (error == OkHttpCallback.RESPONSE_CANCELED) { failure(API_STATUS_CANCELED, "请求取消"); } else { failure(API_STATUS_NET_ERROR, "亲,您的网络不给力!"); } } };
建一个OKHttpUtil:
public static <T> void post(String url, OkRequestParams postBodyParams, Object tag, boolean isProgress, boolean commonParams, OkHttpCallback<T> okHttpCallback) { //这里可以添加公共参数 if (commonParams) { OkRequestParams urlComParams = new OkRequestParams(); url = getFinalUrl(url, urlComParams); } else { url = getFinalUrl(url, postBodyParams); } Call call = null; Callback callback = getCallBack(okHttpCallback); try { RequestBody requestBody = (postBodyParams == null ? null : postBodyParams.getRequestBody()); Headers headers = (postBodyParams == null ? null : postBodyParams.getRequestHeaders()); Request request = getRequest(url, requestBody, headers, tag); call = mOkHttpClient.newCall(request); call.enqueue(callback); } catch (Throwable e) { e.printStackTrace(); callback.onFailure(call, new IOException("post", e)); } } public static Request getRequest(String url, RequestBody requestBody, Headers headers, Object tag) { Request.Builder builder = new Request.Builder(); if (requestBody != null) { builder.post(requestBody); } if (headers != null) { builder.headers(headers); } if (tag != null) { builder.tag(tag); } builder.url(url); return builder.build(); }
我们这样写api:
public class TestGetBookApi extends ApiUtil { public String mData; public TestGetBookApi() { super(); } @Override protected String getUrl() { return "http://139.199.89.89/api/v1/books"; } @Override protected void parseData(JSONObject jsonObject) throws Exception { mData = jsonObject.optString(DATA); } }
调用地方:
private void proceedBookApi() { new TestGetBookApi().get(this, "loading", true, false, new ApiListener(){ @Override public void success(ApiUtil api) { Log.d(TAG,"<<<<<<success"); TestGetBookApi api1 = (TestGetBookApi)api; if(api1.mData != null) { mBookArrayList = new Gson().fromJson(api1.mData, new TypeToken<List<Book>>(){}.getType()); mBookMainAdapter.setList(mBookArrayList); } } @Override public void failure(ApiUtil api) { Log.d(TAG,"<<<<<<failure"); } }); }
主体ApiUtil的完整代码是:
public abstract class ApiUtil { public static final String API_STATUS_REJECT_ERROR = "RejectError"; public static final String API_STATUS_NET_ERROR = "NetError"; public static final String API_STATUS_PARSE_ERROR = "ParseError"; public static final String API_STATUS_NONLOGIN = "nonLogin"; public static final String API_STATUS_TIMEOUT = "timeout"; public static final String API_STATUS_CANCELED = "canceled"; private static final int STATUS_CODE_NO_NETWORK_PRE_HTTP = -1001; // 无网络状态码(不发送联网请求) /** * 请求参数列表 */ private OkRequestParams mParams = new OkRequestParams(); /** * 标签,用于扩展保存标识信息 */ private Object mTag = null; /** * 状态码 */ private String mStatus = ""; /** * 状态码信息 */ private String mStatusMessage = ""; /** * 上下文 */ private Context mContext = null; /** * 是否显示加载界面 */ private boolean mShowLoading = true; /** * 数据返回后是否清除加载界面 */ private boolean mDismissLoadingFinished = true; /** * 加载界面字符串 */ private String mLoadingString = null; /** * 是否显示状态信息 */ private boolean mShowStatusMessage = true; /** * API发送监听 */ private ApiListener mApiListener = null; /** * 是否返回主线程 * * @return 默认为true; 如果子类重写返回false,则不允许更新ui,且不能Toast */ protected boolean isBackMainThread() { return true; } /** * 发送监听 */ private OkHttpResJsonHandler mSendListener = new OkHttpResJsonHandler() { @Override protected boolean isPostMainThread() { return isBackMainThread(); } @Override public void onSuccess(Call call, int statusCode, Headers headers, JSONObject response) { if (null != response) { String status = response.optString(STATUS); String statusMessage = response.optString(MESSAGE); if (TextUtils.isEmpty(statusMessage)) { setStatus(status, ApiStatus.getStatusMessage(status)); } else { setStatus(status, statusMessage); } if (isSuccess()) { try { dismissLoading(); onParse(response); if (null != mApiListener) { mApiListener.success(ApiUtil.this); } } catch (Exception e) { e.printStackTrace(); failure(API_STATUS_PARSE_ERROR, mContext.getString(R.string.parse_error)); } } else { if ("failed".equals(getStatus())) { // 兼容data里含有message字段的api 优先级最高 JSONObject data = response.optJSONObject(DATA); if (data != null) { String message = data.optString(MESSAGE); if (!TextUtils.isEmpty(message)) { failure(status, message); } else { message = response.optString(MESSAGE); if (!TextUtils.isEmpty(message)) { failure(status, message); } else { failure(status, getStatusMessage()); } } } } } } else { failure(API_STATUS_PARSE_ERROR, mContext.getString(R.string.parse_error)); } } @Override public void onFailure(Call call, int code, Headers headers, int error, Throwable t) { if (code == 403) { failure(API_STATUS_REJECT_ERROR, "系统繁忙,请稍后再试"); } else if (error == OkHttpCallback.RESPONSE_ERROR_SERVER) { failure(API_STATUS_NET_ERROR, "服务器处理错误"); } else if (error == OkHttpCallback.RESPONSE_ERROR_TIMEOUT) { failure(API_STATUS_TIMEOUT, "服务器处理错误"); } else if (error == OkHttpCallback.RESPONSE_CANCELED) { failure(API_STATUS_CANCELED, "请求取消"); } else { failure(API_STATUS_NET_ERROR, "亲,您的网络不给力!"); } } }; private void failure(String status, String statusMessage) { dismissLoading(); setStatus(status, statusMessage); // 特殊处理,1、当提示信息为未登陆时不弹出toast提示; 2、请求被取消 if (!status.equals(API_STATUS_NONLOGIN) && !status.equals(API_STATUS_CANCELED)) { showStatusMessage(statusMessage); } if (null != mApiListener) { try { mApiListener.failure(ApiUtil.this); } catch (Exception e) { } } } protected ApiUtil() { super(); } public Context getContext() { if (mContext == null) { return PicApplication.getContext(); } return mContext; } /** * 判断状态码是否成功 * * @return */ public boolean isSuccess() { return ApiStatus.isSuccess(getStatus()); } /** * 获取状态码 * * @return:状态码 */ public String getStatus() { return mStatus; } /** * 设置状态码 * * @param status :状态码 */ public void setStatus(String status) { mStatus = status; } /** * 获取状态信息 * * @return:状态信息 */ public String getStatusMessage() { return mStatusMessage; } /** * 设置状态码及错误信息 * * @param status :状态码 * @param statusMessage :状态信息 */ public void setStatus(String status, String statusMessage) { mStatus = status; mStatusMessage = statusMessage; } /** * 添加参数 * * @param key * @param value */ public void addParam(String key, String value) { mParams.put(key, value); } /** * 获取url * @return:http链接url */ protected abstract String getUrl(); /** * 解析数据 * * @param jsonObject */ private void onParse(JSONObject jsonObject) throws Exception { parseData(jsonObject); } /** * 解析数据 * * @param jsonObject */ protected abstract void parseData(JSONObject jsonObject) throws Exception; /** * http post * * @param context :上下文 * @param loadingString :加载界面显示的提示文字, 如果传空将不显示加载界面 * @param dismissLoading :请求响应后是否销毁加载界面 * @param showStatusMessage :是否在出错时显示出错信息 * @param listener :请求响应监听 */ public void post(Context context, String loadingString, boolean dismissLoading, boolean showStatusMessage, ApiListener listener) { post(context, !TextUtils.isEmpty(loadingString), loadingString, dismissLoading, showStatusMessage, listener); } /** * http post * * @param context :上下文 * @param showLoading :是否显示加载界面 * @param loadingString :加载界面文字, 如果为空将显示默认文字 * @param dismissLoading :请求完成后是否清除加载界面 * @param showStatusMessage :是否显示出错信息 * @param listener :发送回调 */ public void post(Context context, boolean showLoading, String loadingString, boolean dismissLoading, boolean showStatusMessage, ApiListener listener) { init(context, showLoading, loadingString, dismissLoading, showStatusMessage, listener); post(); } /** * http get * * @param context :上下文 * @param loadingString :加载界面显示的提示文字, 如果传空将不显示加载界面 * @param dismissLoading :请求响应后是否销毁加载界面 * @param showStatusMessage :是否在出错时显示出错信息 * @param listener :请求响应监听 */ public void get(Context context, String loadingString, boolean dismissLoading, boolean showStatusMessage, ApiListener listener) { get(context, !TextUtils.isEmpty(loadingString), loadingString, dismissLoading, showStatusMessage, listener); } /** * http get * * @param context :上下文 * @param showLoading :是否显示加载界面 * @param loadingString :加载界面文字, 如果为空将显示默认文字 * @param dismissLoading :请求完成后是否清除加载界面 * @param showStatusMessage :是否显示出错信息 * @param listener :发送回调 */ public void get(Context context, boolean showLoading, String loadingString, boolean dismissLoading, boolean showStatusMessage, ApiListener listener) { init(context, showLoading, loadingString, dismissLoading, showStatusMessage, listener); get(); } /** * 无网络时模拟失败发送失败消息 */ private void post() { if (Util.hasNetwork(mContext)) { OkHttpUtil.post(getUrl(), mParams, mTag, mSendListener); } else if (mSendListener != null) { mSendListener.onFailure(null, STATUS_CODE_NO_NETWORK_PRE_HTTP, null, OkHttpCallback.RESPONSE_ERROR_NET, new Throwable("recvfrom failed: ECONNRESET (Connection reset by peer)")); } } /** * 无网络时模拟失败发送失败消息 */ private void get() { if (Util.hasNetwork(mContext)) { OkHttpUtil.get(getUrl(), mParams, mTag, mSendListener); } else if (mSendListener != null) { mSendListener.onFailure(null, STATUS_CODE_NO_NETWORK_PRE_HTTP, null, OkHttpCallback.RESPONSE_ERROR_NET, new Throwable("recvfrom failed: ECONNRESET (Connection reset by peer)")); } } /** * 初始化发送请求 * * @param context :上下文 * @param showLoading :是否显示加载界面 * @param loadingString :加载界面文字, 如果为空将显示默认文字 * @param dismissLoading :请求完成后是否清除加载界面 * @param showStatusMessage :是否显示出错信息 * @param listener :发送回调 */ private void init(Context context, boolean showLoading, String loadingString, boolean dismissLoading, boolean showStatusMessage, ApiListener listener) { if (null == context) { context = PicApplication.getContext(); } mContext = context; mApiListener = listener; mShowLoading = showLoading; mLoadingString = loadingString; mDismissLoadingFinished = dismissLoading; mShowStatusMessage = showStatusMessage; showLoading(); } /** * 设置loading对话栏显示信息 * * @return */ protected String getDialogMessage() { if (TextUtils.isEmpty(mLoadingString)) { return mContext.getString(R.string.loading); } else { return mLoadingString; } } /** * 显示加载界面 */ protected void showLoading() { if (mShowLoading) { DialogUtil.showLoadingDialog(mContext, getDialogMessage()); } } /** * 清除加载界面 */ protected void dismissLoading() { // 成功时判断是否清除加载界面,失败时不判断是否清除直接清除加载界面 if ((!isSuccess()) || mDismissLoadingFinished) { DialogUtil.dismissLoadingDialog(mContext); } } /** * 显示出错信息 * * @param message */ protected void showStatusMessage(String message) { if (mShowStatusMessage && !TextUtils.isEmpty(message)) { Toast.makeText(mContext,message,Toast.LENGTH_SHORT).show(); } } protected String getString(int resId) { String result = ""; if (null != mContext) { result = mContext.getString(resId); } return result; } }