MVP架构---网络框架切换
项目开发的过程中,随着版本不断迭代,可能要整体去换某一个框架,比如网络框架。常用的网络框架有retrofit、okhttp、okgo、RxUtls、volley,项目开发过程中,可能以前用的volley,现在我们要全部改成retrofit或者okhttp,用一行代码切换框架。以前的做法是每个代码用到这些框架的地方都要改,如果代码量很大,是一件非常痛苦的事情。不管是网络数据库还是图片加载,其实都是同一个思路,接下来会以网络请求为例。
这里我们引入一个隔离层的概念,这个隔离层的作用是帮助我们选择框架。可以用动态代理来实现
image.png设想一个场景,客户要去买房,一般会找房产公司,房产公司会交代业务员去协助,那么业务员会去查找房源,这些房源是业主放出来的。最后,房产公司具备了卖房的能力。实际上是由业务员去完成这个卖房的功能的,他要跟业主进行交流需求。那么这个业务员,会持有这个业主的引用。那么右边用红色框圈起来的其实就是个动态代理。跟着上一篇的demo,新建一个library(专门干网络加载的事情)
为了方便,首先我们新建一个library,然后让MVP的工程依赖这个library,在library里面添加网络库和Gson解析库,因为真正去实现网络操作是在library里面。我们现在添加三种不同的网络请求库
implementation 'com.android.volley:volley:1.1.0'
implementation 'com.google.code.gson:gson:2.2.4'
implementation 'com.squareup.okhttp3:okhttp:3.4.1'
implementation 'org.xutils:xutils:3.3.36'
- 新建一个IHttpProcessor(相当于房产公司)主要进行网络操作
/**
* 房产公司
*/
public interface IHttpProcessor {
/**
* 网络操作 get post del update put select.......
*/
void post(String url, Map<String, Object> params, ICallback callback);
}
- 新建ICallBack顶层接口,IHttpProcessor接口里面的方法会用到,回调数据用于解析
/**
* 顶层回调接口(json,xml,....)
*
*/
public interface ICallback {
void onSuccess(String result);
void onFailure(String e);
}
- 新建HttpCallback,主要是用户接收到json版本的数据后,解析成对应的对象
这里需要注意一下,Result你就当成泛型吧
请求成功后会给你返回result的String类型数据,我们需要把这个String数据转化成所对应的对象。
Gson解析需要一个Class文件clz, Result objResult=(Result)gson.fromJson(result,clz);
可以用analysisClassInfo得到参数化类型,通过反射拿到所需要的对象类型
这样我们在HttpCallback<Result>这个类中,到时候传什么类型,就会回传给我什么类型的数据
/**
* 回调接口的json版本的实现类
* 用于把网络返回的json字符串转让换成对象(Result就是用户接收数据的类型)
* //ResponceData就是Result
*/
public abstract class HttpCallback<Result> implements ICallback {
@Override
public void onSuccess(String result) {//result就是网络回来的数据
//result把转换成用户需要的对象
Gson gson=new Gson();
//需要得到用户输入的对象对应的字节码是什么样的
//得到用户接收数据的对象对应的class
Class<?> clz=analysisClassInfo(this);
Result objResult=(Result)gson.fromJson(result,clz);
//把已经转好的对象,交给用户
onSuccess(objResult);
}
public abstract void onSuccess(Result result);
private Class<?> analysisClassInfo(Object object) {
//getGenericSuperclass可以得到包含原始类型,参数化类型,数组,类型变量,基本数据
Type genType=object.getClass().getGenericSuperclass();
//获取参数化类型
Type[] params=((ParameterizedType)genType).getActualTypeArguments();
return (Class<?>)params[0];
}
@Override
public void onFailure(String e) {
}
}
- 最后我们新建一个HttpHelper,相当于代理类(业务员),去执行房产公司的需求
里面有个post请求,通过优化,以后get和post都可以通用。
/**
* 代理类(业务员)
*/
public class HttpHelper implements IHttpProcessor{
//单例
private static HttpHelper instance;
public static HttpHelper obtain(){
synchronized (HttpHelper.class){
if(instance==null){
instance=new HttpHelper();
}
}
return instance;
}
private HttpHelper(){}
private static IHttpProcessor mIHttpProcessor;
//定义一个API,用来设置代码的接口(业务员找到一个对应的有房的人)
public static void init(IHttpProcessor iHttpProcessor){
mIHttpProcessor=iHttpProcessor;
}
@Override
public void post(String url, Map<String, Object> params, ICallback callback) {
//http://www.aaa.bbb/index
//user=jett&pwd=123
//http://www.aaa.bbb/index?&user=jett&pwd=123
String finalUrl=appendParams(url,params);
mIHttpProcessor.post(finalUrl,params,callback);
}
public static String appendParams(String url, Map<String,Object> params) {
if(params==null || params.isEmpty()){
return url;
}
StringBuilder urlBuilder=new StringBuilder(url);
if(urlBuilder.indexOf("?")<=0){
urlBuilder.append("?");
}else{
if(!urlBuilder.toString().endsWith("?")){
urlBuilder.append("&");
}
}
for(Map.Entry<String,Object> entry:params.entrySet()){
urlBuilder.append("&"+entry.getKey())
.append("=")
.append(encode(entry.getValue().toString()));
}
return urlBuilder.toString();
}
private static String encode(String str){
try {
return URLEncoder.encode(str,"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
}
这样通过上面四个类,我们的一个代理层的网络框架就实现了。那么我们新建几个具体的网络请求实现层,比如okhttp,Vollry,Xutls,注意了,这里这三个是我们的备选的网络请求,我们还可以写很多。
okhttp(具体实现层)
public class OkHttpProcessor implements IHttpProcessor{
private OkHttpClient mOkHttpClient;
private Handler myHandler;
public OkHttpProcessor(){
mOkHttpClient=new OkHttpClient();
myHandler=new Handler();
}
private RequestBody appendBody(Map<String,Object> params){
FormBody.Builder body=new FormBody.Builder();
if(params==null || params.isEmpty()){
return body.build();
}
for(Map.Entry<String,Object> entry:params.entrySet()){
body.add(entry.getKey(),entry.getValue().toString());
}
return body.build();
}
@Override
public void post(String url, Map<String, Object> params,final ICallback callback) {
RequestBody requestBody=appendBody(params);
Request request=new Request.Builder()
.url(url)
.post(requestBody)
.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 result=response.body().string();
if(response.isSuccessful()){
myHandler.post(new Runnable() {
@Override
public void run() {
callback.onSuccess(result);
}
});
}
}
});
}
}
volley(具体实现层)
public class VolleyProcessor implements IHttpProcessor{
private static RequestQueue mQueue=null;
public VolleyProcessor(Context context){
mQueue= Volley.newRequestQueue(context);
}
@Override
public void post(String url, Map<String, Object> params,final ICallback callback) {
StringRequest stringRequest=new StringRequest(
Request.Method.POST,
url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
callback.onSuccess(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
}
);
mQueue.add(stringRequest);
}
}
XUtilsProcessor(具体实现层)
public class XUtilsProcessor implements IHttpProcessor{
public XUtilsProcessor(Application app){
x.Ext.init(app);
}
@Override
public void post(String url, Map<String, Object> params,final ICallback callback) {
RequestParams requestParams=new RequestParams(url);
x.http().post(requestParams, new Callback.CommonCallback<String>() {
@Override
public void onSuccess(String result) {
callback.onSuccess(result);
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
}
@Override
public void onCancelled(CancelledException cex) {
}
@Override
public void onFinished() {
}
});
}
}
以上提供了三个网络请求的预选方案,那么我们怎在APP代码里面使用呢?
首先在Application里面选定好一个网络框架。需要哪个就打开哪个,就一行代码,这里初始化后就能拿到一个实例对象。全局实例化后后续方便直接调用。
public class MyApplication extends Application{
@Override
public void onCreate(){
super.onCreate();
//进行框架的选择
HttpHelper.init(new VolleyProcessor(this));
// HttpHelper.init(new OkHttpProcessor());
// HttpHelper.init(new XUtilsProcessor(this));
/*HttpHelper.init(new RetrofitProcessor());*/
}
}
接着我们在真正的model层去利用这个动态代理进行真正的网络请求。
假设我们要去加载这个URL的数据
https://v.juhe.cn/historyWeather/citys?&province_id=2&key=bb52107206585ab074f5e59a8c73875b
新建一个RespnceData类去进行gsonformat
public class ResponceData{
/**
* resultcode : 112
* reason : 当前可请求的次数不足
* result : null
* error_code : 10012
*/
private String resultcode;
private String reason;
private Object result;
private int error_code;
public String getResultcode(){
return resultcode;
}
public void setResultcode(String resultcode){
this.resultcode = resultcode;
}
public String getReason(){
return reason;
}
public void setReason(String reason){
this.reason = reason;
}
public Object getResult(){
return result;
}
public void setResult(Object result){
this.result = result;
}
public int getError_code(){
return error_code;
}
public void setError_code(int error_code){
this.error_code = error_code;
}
}
现在我们在GirlModel里面去进行真正的网络请求
image.png image.png证明真正的进行网络加载了,这里进行网络请求的代码不用变,如果想用不同的网络框架,可以在Application进行选择。如果未来某一天,有一个X类型网络请求框架,我们可以在library里面新建一个叫XProcessor的类,然后把具体的请求实现写进去,在Application里面初始化选择X,而其他代码不需要变化。这就是具体讲了一个使用代理类进行网络请求框架进行变化的一个思路,比如图片的加载等等是一样的道理。
链接:https://pan.baidu.com/s/1It-bVbf_OjhbSuHc8MCCqA
提取码:b71r