项目地址
这一篇我们主要是网络库的封装,这里我们使用的是OkHttp
,做一些简单额Get
,Post
封装,之后到了Room
那里我们再加上缓存
我们首先添加依赖
//okhttp
implementation 'com.squareup.okhttp3:okhttp:4.2.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'
//room
implementation "android.arch.persistence.room:runtime:1.1.1"
implementation "android.arch.lifecycle:extensions:1.1.1"
annotationProcessor 'android.arch.persistence.room:compiler:1.1.1'
annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
//解析json
implementation 'com.alibaba:fastjson:1.2.59'
接着我们新建一个ApiService
类,用于初始化我们网络库
public class ApiService {
protected static final OkHttpClient OK_HTTP_CLIENT;
static {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OK_HTTP_CLIENT = new OkHttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.connectTimeout(30, TimeUnit.SECONDS)
.addInterceptor(loggingInterceptor)
.build();
TrustManager[] trustManagers = new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}};
try {
SSLContext ssl = SSLContext.getInstance("SSL");
ssl.init(null,trustManagers,new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(ssl.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
}
}
里面就是初始化OkHttp
和一些网络相关的东西,接下我们编写Request
类,请求一般都会有请求地址,请求头和请求参数,所以我们定义三个变量,同时加上相应方法
public abstract class Request<T, R extends Request> {
protected String mUrl;
protected HashMap<String, String> mHeaders = new HashMap<>();
protected HashMap<String, Object> mParams = new HashMap<>();
public Request(String url) {
mUrl = url;
}
public R addHeader(String key, String value) {
mHeaders.put(key, value);
return (R) this;
}
public R addParam(String key, Object value) {
if (value == null) {
return (R) this;
}
//int byte char short long double float boolean 和他们的包装类型,但是除了 String.class 所以要额外判断
try {
if (value.getClass() == String.class) {
mParams.put(key, value);
} else {
Field field = value.getClass().getField("TYPE");
Class claz = (Class) field.get(null);
if (claz.isPrimitive()) {
mParams.put(key, value);
}
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
return (R) this;
}
}
这里解释下addParam
那个方法中有个判断是否是基本类型的校验,这块可以使用if/else
实现,也可以通过反射实现,我们首先随便打开一个基本类型的包装类Integer
每个基本类型都有这个TYPE
,我们通过反射拿到变量,然后通过这个变量拿到对应的Class
,Class
类中有个方法可以判断是不是基本类型
这样就省去了一堆if/else
判断
OK,请求分同步和异步,这里我们就都用一个方法execute
,根据入参是否有CallBack
来判断是同步还是异步,我们先写个Callback
public abstract class JsonCallback<T> {
public void onSuccess(ApiResponse<T> response) {
}
public void onError(ApiResponse<T> response) {
}
public void onCacheSuccess(ApiResponse<T> response) {
}
}
我们还要根据Get
请求还是Post
请求来生成不能的Request
,所以我们在我们的Request
这个抽象类中写一个抽象方法提供给子类实现
protected abstract okhttp3.Request generateRequest(okhttp3.Request.Builder builder);
public class GetRequest<T> extends Request<T, GetRequest> {
public GetRequest(String url) {
super(url);
}
@Override
protected okhttp3.Request generateRequest(okhttp3.Request.Builder builder) {
//get 请求把参数拼接在 url后面
String url = UrlCreator.createUrlFromParams(mUrl, mParams);
return builder.get().url(url).build();
}
}
Get
请求是把参数拼接在url后面,这里咱们直接创建一个工具类使用
public class UrlCreator {
public static String createUrlFromParams(String url, Map<String, Object> params) {
StringBuilder builder = new StringBuilder();
builder.append(url);
if (url.contains("?") || url.contains("&")) {
builder.append("&");
}else {
builder.append("?");
}
for (Map.Entry<String, Object> entry : params.entrySet()) {
try {
String value = URLEncoder.encode(String.valueOf(entry.getValue()), "UTF-8");
builder.append(entry.getKey()).append("=").append(value).append("&");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
builder.deleteCharAt(builder.length() - 1);
return builder.toString();
}
}
接着是PostRequest
的实现
public class PostRequest<T> extends Request<T, PostRequest> {
public PostRequest(String url) {
super(url);
}
@Override
protected okhttp3.Request generateRequest(okhttp3.Request.Builder builder) {
//post请求表单提交
FormBody.Builder bodyBuilder = new FormBody.Builder();
for (Map.Entry<String, Object> entry : mParams.entrySet()) {
bodyBuilder.add(entry.getKey(), String.valueOf(entry.getValue()));
}
return builder.url(mUrl).post(bodyBuilder.build()).build();
}
}
然后我们继续回到我们的Request
类中,我们一般项目中返回的信息都是有固定格式的,外层基本上都是一样的,我们只需要里面data
或者result
的东西,所以我们写一个ApiResponse
类,
public class ApiResponse<T> {
public boolean success;
public int status;
public String message;
public T body;
}
这样的话我们就可以通过fastjson
把我们网络请求参数值解析成我们想要的样式,这里需要一个convert
方法,所以我们还需要编写一个工具类
public interface Convert<T> {
T convert(String response, Type type);
}
public class JsonConvert implements Convert {
//默认的Json转 Java Bean的转换器
@Override
public Object convert(String response, Type type) {
JSONObject jsonObject = JSON.parseObject(response);
JSONObject data = jsonObject.getJSONObject("data");
if (data != null) {
Object data1 = data.get("data");
return JSON.parseObject(data1.toString(), type);
}
return null;
}
}
这样我们就可以在Request
类中完成我们剩下的同步和异步方法了
public ApiResponse<T> execute() {
if (mType == null) {
throw new RuntimeException("同步方法,response 返回值 类型必须设置");
}
ApiResponse<T> result = null;
try {
Response response = getCall().execute();
result = parseResponse(response, null);
} catch (IOException e) {
e.printStackTrace();
result = new ApiResponse<>();
result.message = e.getMessage();
}
return result;
}
public void execute(final JsonCallback callback) {
getCall().enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
ApiResponse<T> apiResponse = new ApiResponse<>();
apiResponse.message = e.getMessage();
callback.onError(apiResponse);
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
ApiResponse<T> apiResponse = parseResponse(response,callback);
if (!apiResponse.success) {
callback.onError(apiResponse);
}else {
callback.onSuccess(apiResponse);
}
}
});
}
private Call getCall() {
okhttp3.Request.Builder builder = new okhttp3.Request.Builder();
addHeaders(builder);
okhttp3.Request request = generateRequest(builder);
return ApiService.OK_HTTP_CLIENT.newCall(request);
}
private void addHeaders(okhttp3.Request.Builder builder) {
for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
builder.addHeader(entry.getKey(), entry.getValue());
}
}
private ApiResponse<T> parseResponse(Response response, JsonCallback callback) {
String message = null;
int status = response.code();
boolean success = response.isSuccessful();
ApiResponse<T> result = new ApiResponse<>();
Convert convert = ApiService.sConvert;
try {
String content = response.body().string();
if (success) {
if (callback != null) {
ParameterizedType type = (ParameterizedType) callback.getClass().getGenericSuperclass();
Type argument = type.getActualTypeArguments()[0];
result.body = (T) convert.convert(content, argument);
} else if (mType != null) {
result.body = (T) convert.convert(content, mType);
}
else {
Log.e("request", "parseResponse: 无法解析 ");
}
} else {
message = content;
}
} catch (Exception e) {
message = e.getMessage();
success = false;
status = 0;
}
result.success = success;
result.status = status;
result.message = message;
return result;
}
同时我们在ApiService
中添加几个方法
public static void init(String baseUrl, Convert convert) {
sBaseUrl = baseUrl;
if (convert == null) {
convert = new JsonConvert();
}
sConvert = convert;
}
public static <T> GetRequest<T> get(String url) {
return new GetRequest<>(sBaseUrl + url);
}
public static <T> PostRequest<T> post(String url) {
return new PostRequest<>(sBaseUrl + url);
}
到此基础的网络请求就封装完了,后续会添加缓存