一时兴起的MVP+RxJava+Retrofit的封装录
MVP介绍:
MVP 全称:Model-View-Presenter ;MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。
RxJava介绍:
RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。这就是 RxJava ,概括得非常精准。对RxJava不熟悉的可以看下https://gank.io/post/560e15be2dca930e00da1083这篇文章(我也不是很熟悉,拿来就用而已,手动摊手)。
Retrofit介绍:
public interface BaseView { /** * 显示正在加载view */ void showLoading(); /** * 关闭正在加载view */ void hideLoading(); /** * 显示提示 * @param msg */ void showToast(String msg, int length); /** * 显示请求错误提示 */ void showErr(String errMsg); /** * 获取上下文 * @return 上下文 */ Context getContext(); }
比如现在有个登录需求需要实现,新建一个LoginView,并继承BaseView,使各功能View能自行实现自己的需求;
public interface LoginView extends BaseView { void loginSuccess(); void loginFailure(); }
OK,我们现在有了登录模块的View了,那么,我们可以在相关登录模块的Activitiy,Fragment上实现该LoginView,例如:
public class LoginActivity extends BaseActivity<LoginPresenter> implements LoginView{ @Override public void loginSuccess() { } @Override public void loginFailure() { } }
好的,那么我们的LoginActivity就实现了我们的LoginView功能了,BaseActivity待会会介绍;
View大概就这么多,可以根据具体的功能需求添加删除;
2、Presenter层:由上文提到的,负责逻辑处理;
同样,新建一个BasePresenter类,因为presenter层级的操作是基于View层的,我们需要在BasePresenter每一步操作前判断我们的view是否存在;
public class BasePresenter<V extends BaseView> { private V view; /** * 绑定view,一般在初始化中调用该方法 */ public void attachView(V view){ this.view = view; } /** * 断开view,一般在onDestroy中调用 */ public void detachView(){ this.view = null; } /** * 是否与View建立连接 * 每次调用业务请求的时候都要出先调用方法检查是否与View建立连接 */ public boolean isViewAttached(){ return view != null; } /** * 获取连接的view */ public V getView(){ return this.view; } public Context getContext(){ return this.view.getContext(); } }
如上图,我们可以通过isViewAttached判断view是否存在,如果view已销毁,我们的逻辑处理也没必要继续下去,进行相对应的销毁工作即可;
OK,同样我们来实现功能Presenter,按照View的现在,我们也实现一个登录模块的Presenter,新建一个LoginPresenter抽象类,并将对应的View以泛型参数声明:
public abstract class LoginPresenter extends BasePresenter<LoginView> { /** * 登录方法 */ public abstract void login(String phoneNum, String password); }
然后,我们将具体实现LoginPresenter,新建一个LoginPresenterImpl类,并继承LoginPresenter;
public class LoginPresenterImpl extends LoginPresenter { @Override public void login(String phoneNum, String password) { if (isViewAttached()) { // 实现Login功能 } } }
Ok,现在我们回头来看LoginActivity,将我们对应功能Presenter以泛型参数传入
LoginActivity extends BaseActivity<LoginPresenter>
3、来看看BaseActivity,直接上代码:
public abstract class BaseActivity<T extends BasePresenter> extends FragmentActivity implements BaseView { protected T mPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setupContentView(); initView(); createPresenterAndAttachView(); } @Override protected void onDestroy() { super.onDestroy(); if (mPresenter != null) { mPresenter.detachView(); } } @Override public void showLoading() { Views.getInstance().showTipDialog(Views.TIPDIALOG_LOADING, this); } @Override public void hideLoading() { Views.getInstance().closeTipDialog(); } @Override public void showToast(String msg, int length) { runOnUiThread(() -> Toast.makeText(getContext(), msg, length).show()); } @Override public void showErr(String errMsg) { showToast(errMsg, Toast.LENGTH_LONG); } @Override public Context getContext() { return BaseActivity.this; } protected abstract void createPresenterAndAttachView(); protected abstract void setupContentView(); protected abstract void initView(); }
BaseActivity实现BaseView,将公共功能实现一下,同时我们的Presenter在onDestroy()上将view解绑,同时我也写了几个抽象方法,createPresenterAndAttachView()在该方法中创建Presenter并进行view的连接工作,
其他就可有可无啦,根据自己的想法走吧。
好了,我们现在差不多可以用起来了。来看看LoginActivity的具体实现:
public class LoginActivity extends BaseActivity<LoginPresenter> implements LoginView, View.OnClickListener { @Override protected void createPresenterAndAttachView() { // 实例化Presenter mPresenter = new LoginPresenterImpl(); // view建立连接 mPresenter.attachView(this); } @Override protected void setupContentView() { setContentView(R.layout.activity_login); } @Override protected void initView() { // 初始化界面 } @Override public void loginSuccess() { // 登录成功 } @Override public void loginFailure() { // 登录失败 } @Override public void onClick(View view) { } }
4、上面似乎还少了个Model层,Model层主要是负责数据,如网络访问,数据库查询等操作,该层没有进一步进行封装了,先来看看Presenter层里是怎样跟Model层交互的;
public class LoginPresenterImpl extends LoginPresenter { @Override public void login(String phoneNum, String password) { if (isViewAttached()) { Map<String, Object> params = new HashMap<>(); params.put("phoneNum", phoneNum); params.put("password", password); UserModel.login(getContext(), params, new Callback<LoginResponse>() { @Override public void onSuccess(LoginResponse data) { } @Override public void onFailure(int errCode, String msg) { } }); } } }
如上图,在Presenter具体的逻辑实现中,我们只是简单的调用了Model层进行具体的数据操作;
让我们看看UserModel是怎样做的:
/** * 用户Model */ public final class UserModel { /** * 登录 * @param params * @param callback */ public static void login(Context context, Map<String, Object> params, Callback<LoginResponse> callback) { RetrofitManager.getInstance().createService(UserApi.class).login(params) .compose(RetrofitManager.getInstance().ioMainSchedulers()) .subscribe(new BaseObserver<>(context, callback)); } }
LoginResponse是服务端返回的实体数据,具体如何造就看你服务端具体返回什么了;
Callback是一个通用的接口,如下:
public interface Callback<T> { /** * 数据请求成功 * * @param data */ void onSuccess(T data); /** * 使用网络API接口请求方式时,虽然已经请求成功但是由 * 于{@code msg}的原因无法正常返回数据。 */ void onFailure(int errCode, String msg); }
5、终于到RxJava和Retrofit的使用了,RetrofitManager是一个Retrofit管理类
/** * Retrofit管理类 */ public final class RetrofitManager { private Retrofit retrofit; public static RetrofitManager getInstance() { return RetrofitHelper.manager; } private RetrofitManager() { retrofit = new Retrofit.Builder() .baseUrl(HttpConstants.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); } private static class RetrofitHelper { private static final RetrofitManager manager = new RetrofitManager(); } public <T> T createService(Class<T> clazz) { return retrofit.create(clazz); } public <T> ObservableTransformer<T, T> ioMainSchedulers() { return upstream -> upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); } }
主要就是实现一个单例模式,然后配合RxJava进行使用,如下login接口:
public interface UserApi { @FormUrlEncoded @POST(HttpConstants.LOGIN) Observable<BaseResponse<LoginResponse>> login(@FieldMap Map<String, Object> params); }
Retrofit+RxJava主要是接口返回参数为RxJava的Observable,就是这么简单,深入的我也还没去研究,先用起来吧。
Ok,大概就是这样了。这样的话,我们的各层级进行了应有的解耦,代码也干净了很多。但是,代码量我觉得是多了的。
自己随手记录的一些内容,相当于是复习了下RxJava,Retrofit的使用和Mvp的概念,不喜勿喷。