前言:
现在很多项目,或市面上80%的程序员都存在以下特点:
你写的代码像首诗,我写的代码像坨屎。
你写的代码是艺术,我写的代码是对付。
你的代码体现了高超的技术,我的代码出现了超多的事故。
所以,今天在新项目中封装retrofit,打算做出诗意般的代码,好好封装一下,敲出一手优美的诗。
但是结局却是个打油诗。
而且隔几个小时再看的时候,尼玛这是YY喊麦。
正文:
MVP设计模式,结合Retrofit,在网上找了好多,各种各样,都不是我心中所想的那样,有的甚至只有VP层,把M层当成了一个Bean。呵呵。
我认为M层应该是数据源的获取,而且可以分担部分的Presenter层的负担。令Presenter层代码不冗余。
抽象:
M层中BaseModle,我的demo很简单,可根据实际项目扩展:
/**
*/
public abstract class IBaseModle {
public abstract void setListener(IBasePrecenter.IBaseDataListener listener);
}
抽象的M层,由于当前项目需求不明确,所以只有一个为当前Modle设置监听。这个监听的接口定义在Precenter的抽象中,因为是P层要调M层,所以这个接口定义就定义在这里的话,给人感觉比较直观。
View层的IBaseView:
public abstract interface IBaseView {
public abstract void onDataSuccess(Object o, int requestCode);
public abstract void onDataError(Object o, int requestCode);
}
抽象出了两个方法,分别是加载成功的回调,和加载失败的回调,这些回调中去操作UI。MV层解耦初步展现,操作UI和业务逻辑与数据加载分开定义。
P层的IBasePrecenter:
/**
* 处理类超类
* T 请求类型
* E 错误返回类型,一般是String,返回错误信息
* J 请求返回类型
* Y 中间件返回类型
*/
public abstract class IBasePrecenter {
public interface IBaseDataListener<T extends Object, E extends Object, J extends Object, Y extends Object> {
//中间本地处理
public Y onPipeline(T request, J response);
//成功回调
public void onDataSuccess(Y o, int requestCode);
//错误回调
public void onDataError(E o, int requestCode);
}
//构造方法调用初始化
public IBasePrecenter() {
initPrecenter();
}
public abstract void initPrecenter();
}
P层的抽象中,定义了一个接口,用于P层中调用M层的时候与M层解耦,效果不好。
这个接口使用泛型,支持中间管道式数据处理,用于自己定制自己的逻辑。
在获取到数据之后的处理,写在这个中间的管道方法中。
此抽象有待完善,现估应该抽象出next()方法,适配更多种情况。同时,抽象出更多的next重载方法,加强管道的数据处理能力。比如说,单个数据如何处理,多个数据如何处理,不想处理时,直接调用next的空参数方法,进行对应的listener回调。
抽象层设计完毕,接下来是实现类们。
实现:
M层的LoginModle:
/**
*/
public class LoginModle extends IBaseModle {
//管道回调
private IBasePrecenter.IBaseDataListener listener;
//请求路径
private String path = "/sb/login.json";
//设置管道回调
@Override
public void setListener(IBasePrecenter.IBaseDataListener listener) {
this.listener = listener;
}
//调用RetrofitService进行网络请求
public void doLogin(UserBean o, final int req) {
RetrofitService.getRetrofitService()
.doPost(o, req, path, listener);
}
}
主要设置了管道listener,然后调用Retrofit封装好的方法,进行网络请求。Retrofit的具体封装,在下面会有。
参数中UserBean o就是请求实体,int req是请求码,在页面通过请求码来判断对应的请求。
View层的ILoginView:
/**
*/
public interface ILoginView extends IBaseView {
@Override
void onDataSuccess(Object o, int requestCode);
@Override
void onDataError(Object o, int requestCode);
}
View层可以根据具体需要再多定制自己的方法。现在本demo中,只有数据加载成功和失败的回调。
P层的LoginPresenter:
/**
* 登陆处理类
*/
public class LoginPrecenter extends IBasePrecenter {
//MVP Modle
private LoginModle modle;
//管道回调
private IBaseDataListener<UserBean, String, UserBean, UserBean> listener;
//MVP View
private IBaseView view;
//构造方法接收View层
public LoginPrecenter(IBaseView view) {
this.view = view;
}
//调用M层进行逻辑处理
public void doLogin(UserBean o, int requestCode) {
modle.doLogin(o, requestCode);
}
/**
* 初始化控制器Presenter层
* 包括:
* 1、 初始化Modle层
* 2、 实现管道回调逻辑
*/
@Override
public void initPrecenter() {
modle = new LoginModle();
listener = new IBaseDataListener<UserBean, String, UserBean, UserBean>() {
/**
* 管道中间处理逻辑
* @param request 请求Bean 泛型中第一个类
* @param response 返回Bean 泛型中第三个类
* @return 将request与Response处理过的Bean 泛型中第四个类
*/
@Override
public UserBean onPipeline(UserBean request, UserBean response) {
/*
进行中间处理......
*/
return response;
}
/**
* 成功回调
* @param o 处理后的Bean 泛型中第三个类
* @param requestCode 请求码
*/
@Override
public void onDataSuccess(UserBean o, int requestCode) {
/*
回调View层,进行UI操作
*/
view.onDataSuccess(o, requestCode);
}
/**
* 失败回调
* @param o 失败信息 泛型中第二个类
* @param requestCode 请求码
*/
@Override
public void onDataError(String o, int requestCode) {
/*
回调View层,进行UI处理
*/
view.onDataError(o, requestCode);
}
};
//将管道回调怼进M层
modle.setListener(listener);
}
}
P层主要做的事有:
1、获取到V层(构造方法中)。
2、获取到M层(initPrecenter方法中)。
3、利用管道回调接口,将M与P关联。
4、调用M层处理业务,处理结果中调用V层操作UI,解耦M层V层。
5、可以在管道中对结果进行拦截,修改,处理定制任务再分发。
至此MVP解耦,并对加载数据进行拦截操作,规范又优雅的实现了定制任务。
目前只是完成了对管道接口的实现,自己定制的业务直接写在onPipeline方法中,规范了代码,后期完善过后,将会出现更强大的功能。(写到这里,发现和RxJava2.+的管道有些像,我仿佛封装了一个RxJava)。
可以发现P层中的管道监听接口的实现,是不是有些像AsyncTask?只要在声明的时候,写好三个对应的泛型,在AS中,就会自动实现,效率贼高。
Retrofit工具类:
/**
*/
public class RetrofitUtil {
public static Retrofit retrofit;
public static String BASE_URL = ServerParams.getBaseUrl();
//创建获取retrofit实例
public static Retrofit buildRetrofit() {
if (retrofit == null) {
synchronized (RetrofitUtil.class) {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
}
}
return retrofit;
}
/**
* 通用post方法。
*/
public interface RetrofitPost {
@POST("{path}")
Call<Object> retrofitPost(@Body Object t, @Path("path") String path);
}
/**
* 通用post方法
*
* @param <T>
*/
public interface RetrofitGet<T> {
@GET("{path}")
Call<T> retrofitGet(@Path("path") String path);
}
}
此工具类,单例模式。通用的post方法之前也是利用泛型设计,但是利用泛型会在调用Retrofit源码的,返回Call< T >的create方法出错。于是post的方法封装没有用泛型,而是直接利用“万物皆Object大法”。
Retrofit业务类:
/**
* 网络请求类
*/
public class RetrofitService {
/**
* 单例模式
*/
private RetrofitService() {
}
private static RetrofitService retrofitService;
/**
* 单例模式获取Service
*
* @return this
*/
public static RetrofitService getRetrofitService() {
if (retrofitService == null) {
synchronized (RetrofitService.class) {
retrofitService = new RetrofitService();
}
}
return retrofitService;
}
/**
* 公用POST方法
*
* @param o Post的请求实体
* @param requestCode 请求码
* @param path 请求路径
* @param listener 请求的控制器,用于回调
*/
public void doPost(final Object o, final int requestCode, String path, final IBasePrecenter.IBaseDataListener listener) {
RetrofitUtil
.buildRetrofit()
.create(RetrofitUtil.RetrofitPost.class)
.retrofitPost(o, path)
.enqueue(new Callback<Object>() {
@Override
public void onResponse(Call<Object> call, Response<Object> response) {
Object piped;//经处理过的中间件
if (response.isSuccessful()) {//请求成功,返回码大于等于200小于300
//中间处理
piped = listener.onPipeline(o, response.body());
if (piped != null)
//处理过
listener.onDataSuccess(piped, requestCode);
else
listener.onDataError("管道处理失败", requestCode);
} else
listener.onDataError(response.code(), requestCode);
}
@Override
public void onFailure(Call<Object> call, Throwable t) {
listener.onDataError("请求失败", requestCode);
}
});
}
/**
* 通用GET方法
*
* @param o GET的实体类,一般没有
* @param requestCode 请求码
* @param path 请求路径
* @param listener 回调控制器
*/
public void doGet(Object o, final int requestCode, String path, final IBasePrecenter.IBaseDataListener listener) {
RetrofitUtil.buildRetrofit()
.create(RetrofitUtil.RetrofitGet.class)
.retrofitGet(path)
.enqueue(new Callback<Object>() {
@Override
public void onResponse(Call<Object> call, Response<Object> response) {
if (response.isSuccessful())
listener.onDataSuccess(response.body(), requestCode);
else
listener.onDataError(response.code(), requestCode);
}
@Override
public void onFailure(Call<Object> call, Throwable t) {
listener.onDataError("请求失败", requestCode);
}
});
}
}
Service层,单例模式获取。由于之前的封装结合Retrofit,在这里的公用Post方法中可以进行链式操作。
其中:
RetrofitUtil .buildRetrofit()返回Retrofit实例
.create(RetrofitUtil.RetrofitPost.class) 返回一个Call< RetrofitPost >
.retrofitPost(o, path) 回一个Call< Object >。
这里对管道的方法进行了调用,管道方法继续完善过后,可以自定义一些强大的方法,YY请参考RxJava。
LoginActivity中,简单介绍下:
首先应该实现View层接口:
public class LoginActivity extends BaseFragmentActivity implements ILoginView {
其次获取一个P层实例:
private LoginPrecenter precenter;
//中间相隔若干行代码
precenter = new LoginPrecenter(this);
实现View层回调,我这里只写了一个,登陆失败的回调:
@Override
public void onDataSuccess(Object o, int requestCode) {
}
@Override
public void onDataError(Object o, int requestCode) {
Intent intent = new Intent();
intent.putExtra(Param.LOGIN_RESULT,Param.LOGIN_CACEL);
setResult(RESULT_CANCELED,intent);
finish();
}
最后,通过P层去跑逻辑:
//登录
loginBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
userName = inputNameEt.getText().toString().trim();
password = inputPwdEt.getText().toString().trim();
userBean.setUserName(userName);
userBean.setUserPwd(password);
precenter.doLogin(userBean, DOLOGIN);
}
});
至此,一个封装好的管道式MVP设计模式的Retrofit网络加载框架就封装完毕。
调用起来非常简单:
1、定义Modle继承自IBaseModle。
2、Modle中调用封装好的retrofit加载网络。
3、定义Presenter继承自IBasePresenter。
4、管道中定制自己需要的方法,数据加载成功失败回调View层。
5、实现View层。
PS:在Modle层中,可以不用公用doPost方法,自己定义特殊的,符合情景的Post方法。
明天上传GitHub。太晚了,睡觉。