最近一个项目在使用okhttp 这里记录一下使用过程,关于okhttp的使用网上已经有很多讲解,下面说一下本人在项目中使用过程中对其进行的简单封装
直接进入主题
使用okhttp首先要在gradle.build里面加入
compile 'com.squareup.okhttp:okhttp:2.6.0'
我定义了一个接口api规范一下我的请求函数
import android.content.Context;
/**
* Created by lkk on 2016/5/10.
*/
public interface Api {
<span style="white-space:pre"> </span>// API域名
public static final String API_BASE_DOCTOR = "";//
/**
* 登陆
*
* @param context
* @param vCode 验证码
* @param phone 手机号
*/
void login(Context context, String vCode, String phone, ResultCallback callback);
/**
* 发送验证码
*
* @param context
* @param phone 手机号
*/
void sendCode(Context context, String phone, ResultCallback callback);
}
这里简单定义了两个请求, Context参数是因为后面提取header信息要用到, ResultCallback用来回调通知请求结果看代码
import com.google.gson.internal.$Gson$Types;
import com.squareup.okhttp.Request;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* Created by Administrator on 2015/12/5 0005.
* <p/>
* 回调函数
* 请求事件结果通知
*/
public abstract class ResultCallback<T> {
public Type mType;
public ResultCallback() {
mType = getSuperclassTypeParameter(getClass());
}
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]);
}
/**
* 网路请求失败
*
* @param request
* @param e
*/
public void onFailure(Request request, Exception e) {
}
/**
* 网路请求错误
*
* @param code
* @param message
*/
public void onError(int code, String message) {
}
/**
* 请求服务器成功
*
* @param response
*/
public void onResponse(T response) {
}
/**
* 请求完成
*/
public void onFinish() {
}
/**
* 请求开始
*/
public void onStart() {
}
}
mType是拿到数据gson解析成的对象类型,有了它string变对象模型就easy了,这里我定义了 onStart和onFinish回调函数是因为我要在这里处理progressDialog
下面是我定义的一个抽象类来收集请求参数数据
import android.content.Context;
import com.squareup.okhttp.Request;
import java.util.TreeMap;
/**
* Created by lkk on 2016/5/10.
* 代理操作 收集请求数据
* 调用实现
*/
public abstract class AbsGateway implements Api {
/** 登录 */
String API_LOGIN = "";
/**发送验证码*/
private static final String API_SEND_CODE = "";
private static AbsGateway mInstance;
public static AbsGateway getInstance() {
synchronized (AbsGateway.class){
if (mInstance == null) {
mInstance = new GatewayImp();
}
}
return mInstance;
}
@Override
public void login(Context context, String vCode, String phone, ResultCallback callback) {
TreeMap<String, String> mParam = new TreeMap<String, String>();
mParam.put("verify_code", vCode);
mParam.put("phone", phone);
deliveryResult(context, callback, getOrderParamString(context, API_LOGIN, mParam));
}
@Override
public void sendCode(Context context, String phone, ResultCallback callback) {
TreeMap<String, String> mParam = new TreeMap<String, String>();
mParam.put("phone", phone);
deliveryResult(context, callback, getOrderParamString(context, API_SEND_CODE, mParam));
}
/**
* 发出请求 以及处理返回结果执行回调
* @param cxt
* @param callback
* @param request
*/
abstract void deliveryResult(Context cxt, ResultCallback callback, Request request);
/**
* 参数 排序加密处理
* @param context
* @param url 接口地址(不包含域名)
* @param mParam 参数集合
* @return 返回Request对象
*/
abstract Request getOrderParamString(Context context, String url, TreeMap mParam);
}
这里定义了我的接口地址和接口请求回调上面两个抽象函数注释已经很明确了就不介绍了, 由于加密前需要对参数进行字母表顺序排序所以我用了TreeMap进行存储
再来看下面的实现类
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.widget.Toast;
import com.google.gson.Gson;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.FormEncodingBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import java.io.IOException;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.util.Iterator;
import java.util.TreeMap;
/**
* Created by lkk on 2016/5/10.
*
* 实现发起网络请求事件
* 实现请求数据排序加密操作
* 处理网络请求返回的数据
* 执行回调事件
*/
public class GatewayImp extends AbsGateway{
protected OkHttpClient client = new OkHttpClient();
public Handler mHandle;
public Gson mGson;
public GatewayImp() {
client = new OkHttpClient();
//cookie enabled
client.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER));
mHandle = new Handler(Looper.getMainLooper());
mGson = new Gson();
}
@Override
void deliveryResult(final Context cxt, final ResultCallback callback, Request request) {
if (!SystemInfo.isNetworkConnected(cxt)) {
Toast.makeText(cxt,
cxt.getString(R.string.toast_not_network), Toast.LENGTH_SHORT).show();
return;
}
if (callback != null) {
callback.onStart();
}
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(final Request request, final IOException e) {
onFailuerMessage(callback, request, e);
}
@Override
public void onResponse(final Response response) {
try {
if (response.code() != 200) {
onErrorMessage(callback, response.code(), response.message());
return;
}
String str = response.body().string().toString();
if (!TextUtils.isEmpty(str.trim())) {
Result mResult = mGson.fromJson(str, callback.mType);
parse(cxt, callback, mResult);
}
} catch (Exception e) {
LogInfo.e("parse exception is: " + e.toString());
}
}
});
}
@Override
Request getOrderParamString(Context context, String url, TreeMap mParam) {
FormEncodingBuilder builder = new FormEncodingBuilder();
String timestamp = String.valueOf(System.currentTimeMillis());
String uuid = SystemInfo.getIMEI(context);//获取IMEI
String version = PackageUtils.getAppVersion(context);//这里获取版本号
String app_key = "加密协议字符串";
Iterator<String> iter = mParam.keySet().iterator();
String key;
while (iter.hasNext()) {
key = iter.next();
builder.add(key, String.valueOf(mParam.get(key)));
}
String paramsStr = URLEncodedUtils.format(mParam, HTTP.UTF_8);
String signature = Tools.getMD5(Config.PLATFORM + app_key + uuid + version + paramsStr + timestamp);
return buildRequest(context, builder, API_BASE_DOCTOR + url, version, uuid, signature, timestamp);
}
/**
* <br>post异步请求<br>
* 获取请求头信息
*
* @param url
* @return
*/
private Request buildRequest(Context cxt, FormEncodingBuilder builder, String url, String version, String uuid, String signature, String timestamp) {
Request request = new Request.Builder()
.url(url)
.header("User-Agent", "OkHttp Headers.java")
.addHeader("Accept", "application/json; q=0.5")
.addHeader("Accept", "application/vnd.github.v3+json")
.addHeader("X-VERSION", version)
.addHeader("X-VerName", version)
.addHeader("X-VerCode", version)
.addHeader("X-Platform", Config.PLATFORM)
.addHeader("X-Device", Build.DEVICE)
.addHeader("X-Uuid", uuid)
.addHeader("X-BuildVersion", Build.VERSION.RELEASE)
.addHeader("timestamp", timestamp)
.addHeader("signature", signature)
.post(builder.build())
.build();
return request;
}
/**
* 服务器没有响应
*
* @param callback
* @param request
* @param e
*/
private void onFailuerMessage(final ResultCallback callback, final Request request, final IOException e) {
mHandle.post(new Runnable() {
@Override
public void run() {
callback.onFailure(request, e);
callback.onFinish();
}
});
}
/**
* 服务器没有响应
*
* @param callback
* @param code
* @param message
*/
private void onErrorMessage(final ResultCallback callback, final int code, final String message) {
mHandle.post(new Runnable() {
@Override
public void run() {
callback.onError(code, message);
callback.onFinish();
}
});
}
/**
* 解析数据
* 转成主线程回调
*
* @param callback
* @param mResult
*/
private void parse(final Context cxt, final ResultCallback callback, final Result mResult) {
mHandle.post(new Runnable() {
@Override
public void run() {
if (mResult.getCode() == 1) {
callback.onResponse(mResult);
} else {
callback.onResponse(mResult.getCode(), mResult.getMsg());
}<pre name="code" class="java"><span style="white-space:pre"> </span>callback.onFinish();
} }); }
该类完成了父类定义的两个抽象类的实现 , 后面再添加接口这里就不用改动的
deliveryResult 执行我的okhttp请求 并对请求回来的数据进行解析, callback.mType 就是前面提到的数据对象类型
getOrederParamString 完成参数加密逻辑
buildRequest 添加头信息参数
parse 请求成功拿到数据 进行回调, 由于okHttp已经处理好了异步请求,包含回调也是异步这里我用了一个handle当作主线程回调
该实现类完成之后后面增加请求接口只需在api里面定义, 在抽象类里调用就ok了,
请求时这样调用:
private void reqLogin(){
AbsGateway.getInstance().login(this, "", "", callback);
}
ResultCallback callback = new ResultCallback<User>(){
@Override
public void onStart() {
//显示 progressDialog
}
@Override
public void onResponse(User response) {
<span style="white-space:pre"> </span>//请求到数据
}
@Override
public void onFinish() {
// 关闭 progressDialog
}
};
注: 这里只是实现了okHttp的post请求, 还有get请求和HTTP方式文件上传 , 好像android4.4源码里 HttpURLConnection已经被okHttp替代了更说明了它的潜力