一、六大原则
1.1 单一职责原则:
英文:Single Responsibility Principle
定义:就一个类而言,应该仅有一个引起它变化的原因。简单来说,一个类中应该是一组相关性很高的函数、数据的封装。
请求和缓存完全写到了一堆
小插曲:链式调用,调用方式有问题 ,比如 超时重连,超时时间 ,支持cookie 等等,更多的是关注业务逻辑
问题? xUtils Okhttp Retrofit …… 切换第三方的网络框架
1.2 开闭原则:
英文:Open Close Principle
定义:软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是,对于修改是封闭(关闭)的。
当软件需要变化时,应该尽量通过扩展的方式来实现变化,而不是通过修改已有的代码来实现。
1.3 里氏替换原则:
英文:Liskov Substitution Principle
定义:只要父类能出现的地方子类就可以出现,主要体现就是实现和继承
1.4 依赖倒置原则:
英文:Dependence Inversion Principle
定义:指代了一种特定的解耦形式,高层模块不依赖低层次模块的细节,说白了高层次就是不依赖细节而是依赖抽象。
高层和底层,HttpUtils 1 IHttpRequest 2 OKHttpRequest 3 XutilsHttpRequest 4 高层 1 2 底层 3 4
1.5 接口隔离原则:
英文:Interface Segregation Principle
定义:类间的依赖关系应该建立在最小的接口上。接口隔离原则将非常庞大、臃肿的接口拆分成为更小的和更具体的接口,这样客户将会只需要知道他们感兴趣的方法。接口隔离原则的目的是系统解开耦合,从而容易重构、更改和重新部署,让客户端依赖的接口尽可能地小。(接口拆分,单接口)
上面的这个五个原则 其实都更接口和抽象有关 (面向抽象和面向接口)
1.6 迪米特原则:
英文:Law of Demeter
定义:一个对象应该对其他对象有最少的了解,调用者也是比较关注。
二、网络引擎切换
①最基本的使用
/********************访问网络开始*******************/
OkHttpClient mOkHttpClient=new OkHttpClient();
Map<String,Object> params=new HashMap<>();
// 特定参数
params.put("iid", 6152551759L);
params.put("aid", 7);
// 公共参数
params.put("app_name", "joke_essay");
params.put("version_name", "5.7.0");
params.put("ac", "wifi");
params.put("device_id", "30036118478");
params.put("device_brand", "Xiaomi");
params.put("update_version_code", "5701");
params.put("manifest_version_code", "570");
params.put("longitude", "113.000366");
params.put("latitude", "28.171377");
params.put("device_platform", "android");
String jointUrl=Utils.jointParams(ConstantValue.UrlConstant.HOME_DISCOVERY_URL,params);
Log.e("Post请求路径:", jointUrl);
Request.Builder requestBuilder = new Request.Builder().url(jointUrl).tag(this);
Request request = requestBuilder.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 失败
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String resultJson = response.body().string();
Log.e("TAG", resultJson);
// 1.JSON解析转换
// 2.显示列表数据
// 3.缓存数据
}
});
/********************访问网络结束*******************/
②优化一,将请求封装成一个工具类
public class HttpUtils {
private HttpUtils() {
}
public static void get(Context context, String url, Map<String, Object> params, final Callback callback) {
OkHttpClient mOkHttpClient = new OkHttpClient();
// 公共参数
params.put("app_name", "joke_essay");
params.put("version_name", "5.7.0");
params.put("ac", "wifi");
params.put("device_id", "30036118478");
params.put("device_brand", "Xiaomi");
params.put("update_version_code", "5701");
params.put("manifest_version_code", "570");
params.put("longitude", "113.000366");
params.put("latitude", "28.171377");
params.put("device_platform", "android");
String jointUrl = Utils.jointParams(url, params);
Log.e("Post请求路径:", jointUrl);
Request.Builder requestBuilder = new Request.Builder().url(jointUrl).tag(context);
Request request = requestBuilder.build();
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 {
// 1.JSON解析转换
// 2.显示列表数据
// 3.缓存数据
callback.onResponse(call,response);
}
});
}
}
/********************访问网络开始*******************/
Map<String,Object> params=new HashMap<>();
// 特定参数
params.put("iid", 6152551759L);
params.put("aid", 7);
HttpUtils.get(this, ConstantValue.UrlConstant.HOME_DISCOVERY_URL, params, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 失败
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String resultJson = response.body().string();
Log.e("TAG", resultJson);
// 1.JSON解析转换
// 2.显示列表数据
// 3.缓存数据
}
});
/********************访问网络结束*******************/
③优化2,添加缓存
- HttpUtils
public class HttpUtils {
private HttpUtils() {
}
public static <T> void get(Context context, String url, Map<String, Object> params, final HttpCallBack<T> callback, final boolean cache) {
OkHttpClient mOkHttpClient = new OkHttpClient();
// 公共参数
params.put("app_name", "joke_essay");
params.put("version_name", "5.7.0");
params.put("ac", "wifi");
params.put("device_id", "30036118478");
params.put("device_brand", "Xiaomi");
params.put("update_version_code", "5701");
params.put("manifest_version_code", "570");
params.put("longitude", "113.000366");
params.put("latitude", "28.171377");
params.put("device_platform", "android");
final String jointUrl = Utils.jointParams(url, params);
Log.e("Post请求路径:", jointUrl);
//保存数据
final String cacheJson = (String) PreferencesUtil.getInstance().getParam(jointUrl, "");
// 写一大堆处理逻辑 ,内存怎么扩展等等
if (cache && !TextUtils.isEmpty(cacheJson)) {
Gson gson = new Gson();
T objResule = (T) gson.fromJson(cacheJson, Utils.analysisClazzInfo(callback));//Student.class
callback.onSuccess(objResule);
}
Request.Builder requestBuilder = new Request.Builder().url(jointUrl).tag(context);
Request request = requestBuilder.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 失败
callback.onFailure(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String resultJson = response.body().string();
Log.e("TAG", resultJson.equals(cacheJson) + "");
if (cache && !TextUtils.isEmpty(cacheJson)) {
return;
}
// 1.JSON解析转换
// 2.显示列表数据
// 3.缓存数据
Gson gson = new Gson();
T objResult = (T) gson.fromJson(resultJson,
Utils.analysisClazzInfo(callback));
callback.onSuccess(objResult);
if (cache) {
PreferencesUtil.getInstance().saveParam(jointUrl, resultJson);
}
}
});
}
}
- 保存数据工具类
public class PreferencesUtil {
private SharedPreferences preferences;
private SharedPreferences.Editor editor;
private Object object;
public static PreferencesUtil preferencesUtil;
public static PreferencesUtil getInstance() {
//双层检验所
if (preferencesUtil == null) {
synchronized (PreferencesUtil.class) {
if (preferencesUtil == null) {
preferencesUtil = new PreferencesUtil();
}
}
}
return preferencesUtil;
}
public void init(Context context) {
//preferences=context.getSharedPreferences("name",Context.MODE_PRIVATE);
preferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
}
/**
* 问题在于,这个Context哪来的我们不能确定,很大的可能性,你在某个Activity里面为了方便,直接传了个this;
* 这样问题就来了,我们的这个类中的sInstance是一个static且强引用的,在其内部引用了一个Activity作为Context,也就是说,
* 我们的这个Activity只要我们的项目活着,就没有办法进行内存回收。而我们的Activity的生命周期肯定没这么长,造成了内存泄漏。
* 所以这里使用context.getApplicationContext()
*/
private PreferencesUtil() {
}
/**
* 保存数据 , 所有的类型都适用
*
* @param key
* @param object string,int,boolean
*/
public synchronized void saveParam(String key, Object object) {
if (editor == null) {
editor = preferences.edit();
String type = object.getClass().getSimpleName();
if ("String".equals(type)) {
// 保存String 类型
editor.putString(key, (String) object);
} else if ("Integer".equals(type)) {
// 保存integer 类型
editor.putInt(key, (Integer) object);
} else if ("Boolean".equals(type)) {
// 保存 boolean 类型
editor.putBoolean(key, (Boolean) object);
} else if ("Float".equals(type)) {
// 保存float类型
editor.putFloat(key, (Float) object);
} else if ("Long".equals(type)) {
// 保存long类型
editor.putLong(key, (Long) object);
} else {
if (!(object instanceof Serializable)) {
throw new IllegalArgumentException(object.getClass().getName() + " 必须实现Serializable接口!");
}
// 不是基本类型则是保存对象
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
String produectBase64 = Base64.encodeToString(baos.toByteArray()
, Base64.DEFAULT);
editor.putString(key, produectBase64);
Log.d(this.getClass().getSimpleName(), "save object success");
} catch (IOException e) {
e.printStackTrace();
}
}
}
editor.commit();
}
/**
* 移除信息
*/
public synchronized void remove(String key) {
if (editor == null) {
editor = preferences.edit();
editor.remove(key);
editor.commit();
}
}
/**
* Whether to use for the first time
*
* @return
*/
public boolean isFirst() {
return (boolean) getParam("isFirst", true);
}
/**
* set user first use is false
*
* @return
*/
public void setFirst(Boolean isFirst) {
saveParam("isFirst", isFirst);
}
/**
* Set up the first time login
*
* @return
*/
public boolean isLogin() {
return (Boolean) getParam("isLogin", false);
}
/**
* @return
*/
public void setLogin(Boolean isLogin) {
saveParam("isLogin", isLogin);
}
/**
* 得到保存数据的方法,所有类型都适用
*/
public Object getParam(String key, Object defaultObject) {
if (defaultObject == null) {//序列化对象
return getObject(key);
}
String type = defaultObject.getClass().getSimpleName();
if ("String".equals(type)) {
return preferences.getString(key, (String) defaultObject);
} else if ("Integer".equals(type)) {
return preferences.getInt(key, (Integer) defaultObject);
} else if ("Boolean".equals(type)) {
return preferences.getBoolean(key, (Boolean) defaultObject);
} else if ("Float".equals(type)) {
return preferences.getFloat(key, (Float) defaultObject);
} else if ("Long".equals(type)) {
return preferences.getLong(key, (Long) defaultObject);
}
return getObject(key);
}
private Object getObject(String key) {
String wordBase64 = preferences.getString(key, "");
byte[] base64 = Base64.decode(wordBase64, Base64.DEFAULT);
ByteArrayInputStream bais = new ByteArrayInputStream(base64);
try {
ObjectInputStream ois = new ObjectInputStream(bais);
object = ois.readObject();
Log.d(this.getClass().getSimpleName(), "Get object success");
return object;
} catch (Exception e) {
e.printStackTrace();
}
Log.e(this.getClass().getSimpleName(), "Get object is error");
return null;
}
}
回调HttpCallback抽象方法
public abstract class HttpCallBack<T> {
// 返回可以直接操作的对象
public abstract void onSuccess(T result);
public abstract void onFailure(Exception e);
}
- MainActivity
/********************访问网络开始*******************/
Map<String,Object> params=new HashMap<>();
// 特定参数
params.put("iid", 6152551759L);
params.put("aid", 7);
HttpUtils.get(this, ConstantValue.UrlConstant.HOME_DISCOVERY_URL, params, new HttpCallBack<DiscoverListResult>() {
@Override
public void onSuccess(DiscoverListResult result) {
if (result.isOK()) {
// 没有列表数据的情况, 打印 Toast 或者做一些其他处理
} else {
// 有数据列表的情况,显示列表
showListData(result);
}
}
@Override
public void onFailure(Exception e) {
}
},true);
/********************访问网络结束*******************/
}
private void showListData(DiscoverListResult result) {
}
优化3,单一原则优化+链式调用:将网络块和缓存块单独提取出来
- HttpUtils
public class HttpUtils {
private Context mContext;
private OKHttpRequest mOkHttpClient;
private final int TYPE_POST = 0x0011, TYPE_GET = 0x0022;
private int mType = TYPE_GET;
private Map<String, Object> mParams;
private String mUrl;
private boolean mCache;
public static HttpUtils with(Context context) {
return new HttpUtils(context);
}
public HttpUtils get() {
mType = TYPE_GET;
return this;
}
public HttpUtils post() {
mType = TYPE_POST;
return this;
}
public HttpUtils addParams(String key, Object value) {
mParams.put(key, value);
return this;
}
public HttpUtils addParams(Map<String, Object> params) {
mParams.putAll(params);
return this;
}
public HttpUtils url(String url) {
this.mUrl = url;
return this;
}
public HttpUtils cache(boolean cache) {
this.mCache = cache;
return this;
}
private HttpUtils(Context context) {
mOkHttpClient = new OKHttpRequest();
mParams = new HashMap<>();
this.mContext = context;
}
public <T> void request(HttpCallBack<T> callback) {
if (mUrl == null) {
throw new RuntimeException("The url cannot be empty");
}
mOkHttpClient.get(mContext, mUrl, mParams, callback, mCache);
}
/* public <T> void get(Context context, String url, Map<String, Object> params, final HttpCallBack<T> callback, final boolean cache) {
mOkHttpClient.get(context, url, params, callback, cache);
}*/
}
- OKHttpRequest
public class OKHttpRequest {
private SPHttpCache mHttpCache;
public OKHttpRequest() {
mHttpCache = new SPHttpCache();
}
public <T> void get(Context context, String url, Map<String, Object> params, final HttpCallBack<T> callback, final boolean cache) {
OkHttpClient mOkHttpClient = new OkHttpClient();
// 公共参数
params.put("app_name", "joke_essay");
params.put("version_name", "5.7.0");
params.put("ac", "wifi");
params.put("device_id", "30036118478");
params.put("device_brand", "Xiaomi");
params.put("update_version_code", "5701");
params.put("manifest_version_code", "570");
params.put("longitude", "113.000366");
params.put("latitude", "28.171377");
params.put("device_platform", "android");
final String jointUrl = Utils.jointParams(url, params);
Log.e("Post请求路径:", jointUrl);
//保存数据
final String cacheJson = mHttpCache.getCache(jointUrl);
// 写一大堆处理逻辑 ,内存怎么扩展等等
if (cache && !TextUtils.isEmpty(cacheJson)) {
Gson gson = new Gson();
T objResule = (T) gson.fromJson(cacheJson, Utils.analysisClazzInfo(callback));//Student.class
callback.onSuccess(objResule);
}
Request.Builder requestBuilder = new Request.Builder().url(jointUrl).tag(context);
Request request = requestBuilder.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 失败
callback.onFailure(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String resultJson = response.body().string();
Log.e("TAG", resultJson.equals(cacheJson) + "");
if (cache && !TextUtils.isEmpty(cacheJson)) {
return;
}
// 1.JSON解析转换
// 2.显示列表数据
// 3.缓存数据
Gson gson = new Gson();
T objResult = (T) gson.fromJson(resultJson,
Utils.analysisClazzInfo(callback));
callback.onSuccess(objResult);
if (cache) {
mHttpCache.saveCache(jointUrl, resultJson);
}
}
});
}
}
- SPHttpCache
public class SPHttpCache {
//sp缓存,内存缓存,文件缓存
public void saveCache(String finalUrl,String resultJson){
PreferencesUtil.getInstance().saveParam(finalUrl,resultJson);
}
public String getCache(String finalUrl){
return (String) PreferencesUtil.getInstance().getObject(finalUrl);
}
}
优化4,Http网络引擎切换
IHttpRequest提供接口,开闭原则:
public interface IHttpRequest {
<T> void get(Context context, String url, Map<String, Object> params,
final HttpCallBack<T> callback, final boolean cache);
<T> void post(Context context, String url, Map<String, Object> params,
final HttpCallBack<T> callback, final boolean cache);
<T> void download(Context context, String url, Map<String, Object> params,
final HttpCallBack<T> callback);
<T> void upload(Context context, String url, Map<String, Object> params,
final HttpCallBack<T> callback);
}
- 修改OkHttpRequest
public class OKHttpRequest implements IHttpRequest{
private SPHttpCache mHttpCache;
public OKHttpRequest() {
mHttpCache = new SPHttpCache();
}
public <T> void get(Context context, String url, Map<String, Object> params, final HttpCallBack<T> callback, final boolean cache) {
OkHttpClient mOkHttpClient = new OkHttpClient();
// 公共参数
params.put("app_name", "joke_essay");
params.put("version_name", "5.7.0");
params.put("ac", "wifi");
params.put("device_id", "30036118478");
params.put("device_brand", "Xiaomi");
params.put("update_version_code", "5701");
params.put("manifest_version_code", "570");
params.put("longitude", "113.000366");
params.put("latitude", "28.171377");
params.put("device_platform", "android");
final String jointUrl = Utils.jointParams(url, params);
Log.e("Post请求路径:", jointUrl);
//保存数据
final String cacheJson = mHttpCache.getCache(jointUrl);
// 写一大堆处理逻辑 ,内存怎么扩展等等
if (cache && !TextUtils.isEmpty(cacheJson)) {
Gson gson = new Gson();
T objResule = (T) gson.fromJson(cacheJson, Utils.analysisClazzInfo(callback));//Student.class
callback.onSuccess(objResule);
}
Request.Builder requestBuilder = new Request.Builder().url(jointUrl).tag(context);
Request request = requestBuilder.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 失败
callback.onFailure(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String resultJson = response.body().string();
Log.e("TAG", resultJson.equals(cacheJson) + "");
if (cache && !TextUtils.isEmpty(cacheJson)) {
return;
}
// 1.JSON解析转换
// 2.显示列表数据
// 3.缓存数据
Gson gson = new Gson();
T objResult = (T) gson.fromJson(resultJson,
Utils.analysisClazzInfo(callback));
callback.onSuccess(objResult);
if (cache) {
mHttpCache.saveCache(jointUrl, resultJson);
}
}
});
}
@Override
public <T> void post(Context context, String url, Map<String, Object> params, HttpCallBack<T> callback, boolean cache) {
}
@Override
public <T> void download(Context context, String url, Map<String, Object> params, HttpCallBack<T> callback) {
}
@Override
public <T> void upload(Context context, String url, Map<String, Object> params, HttpCallBack<T> callback) {
}
}
- 新增XutilsRequest
public class XUtilsRequest implements IHttpRequest{
private SPHttpCache mHttpCache;
public XUtilsRequest() {
mHttpCache = new SPHttpCache();
}
public <T> void get(Context context, String url, Map<String, Object> params, final HttpCallBack<T> callback, final boolean cache) {
RequestParams requestParams = new RequestParams();
x.http().get(requestParams, new org.xutils.common.Callback.CommonCallback<String>() {
@Override
public void onSuccess(String result) {
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
}
@Override
public void onCancelled(CancelledException cex) {
}
@Override
public void onFinished() {
}
});
}
@Override
public <T> void post(Context context, String url, Map<String, Object> params, HttpCallBack<T> callback, boolean cache) {
}
@Override
public <T> void download(Context context, String url, Map<String, Object> params, HttpCallBack<T> callback) {
}
@Override
public <T> void upload(Context context, String url, Map<String, Object> params, HttpCallBack<T> callback) {
}
}
- 修改HttpUtils
public class HttpUtils {
private static IHttpRequest mInitHttpRequest;
private Context mContext;
private IHttpRequest mHttpRequest;
private final int TYPE_POST = 0x0011, TYPE_GET = 0x0022;
private int mType = TYPE_GET;
private Map<String, Object> mParams;
private String mUrl;
private boolean mCache;
public static HttpUtils with(Context context) {
return new HttpUtils(context);
}
private HttpUtils(Context context) {
mHttpRequest = new OKHttpRequest();
mParams = new HashMap<>();
this.mContext = context;
}
public HttpUtils get() {
mType = TYPE_GET;
return this;
}
public HttpUtils exchangeRequest(IHttpRequest httpRequest) {
this.mHttpRequest = httpRequest;
return this;
}
public HttpUtils post() {
mType = TYPE_POST;
return this;
}
public HttpUtils addParams(String key, Object value) {
mParams.put(key, value);
return this;
}
public HttpUtils addParams(Map<String, Object> params) {
mParams.putAll(params);
return this;
}
public HttpUtils url(String url) {
this.mUrl = url;
return this;
}
public HttpUtils cache(boolean cache) {
this.mCache = cache;
return this;
}
public <T> void request(HttpCallBack<T> callback) {
if(mInitHttpRequest==null){
mInitHttpRequest=new OKHttpRequest();
}
if (mUrl == null) {
throw new RuntimeException("The url cannot be empty");
}
mHttpRequest.get(mContext, mUrl, mParams, callback, mCache);
}
public static void initHttpRequest(IHttpRequest httpRequest) {
mInitHttpRequest = httpRequest;
}
/* public <T> void get(Context context, String url, Map<String, Object> params, final HttpCallBack<T> callback, final boolean cache) {
mOkHttpClient.get(context, url, params, callback, cache);
}*/
}
- application添加默认网络引擎
HttpUtils.initHttpRequest(new OKHttpRequest());//默认初始化一个OKhttpRequest
Utils工具类封装:反射获取泛型的类,将Url进行拼接
public class Utils {
private Utils() {
}
/**
* url字符串拼接
*/
public static String jointParams(String url, Map<String, Object> params) {
if (params == null || params.size() <= 0) {//http://baidu.com
return url;
}
StringBuffer stringBuffer = new StringBuffer(url);
if (!url.contains("?")) {
stringBuffer.append("?");
} else {
if (!url.endsWith("?")) {
stringBuffer.append("&");
}
}
//?id=4&name=zhangsan
for (Map.Entry<String, Object> entry : params.entrySet()) {
stringBuffer.append(entry.getKey() + "=" + entry.getValue() + "&");
}
//最后一个肯定是&,要去掉
stringBuffer.deleteCharAt(stringBuffer.length() - 1);
return stringBuffer.toString();
}
/**
* 获得带有泛型的父类
*/
public static Class<?> analysisClazzInfo(Object object) {
Type genType = object.getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
return (Class<?>) params[0];
}
}