首页 » 软件开发 » 搭建属于自己的Android MVP 框架(封装操作蜀黍自己的业务)

搭建属于自己的Android MVP 框架(封装操作蜀黍自己的业务)

南宫静远 2024-07-24 01:46:03 0

扫一扫用手机浏览

文章目录 [+]

头条不允许内嵌GitHub的网址 所以无法配置超链接 需要源码的小伙伴可以留言,无偿奉献给小伙伴们!

关于MVP

- M(Model)负责数据的请求,解析,过滤等数据操作。

- V(View)负责处理UI,通常以`Activity` `Fragment`的形式出现。

搭建属于自己的Android MVP 框架(封装操作蜀黍自己的业务) 软件开发
(图片来自网络侵删)

- P(Presenter)View Model中间件,交互的桥梁。

MVP的好处

- 分离了UI逻辑和业务逻辑,降低了耦合。

- Activity只处理UI相关操作,代码变得更加简洁。

- UI逻辑和业务逻辑抽象到接口中,方便阅读及维护。

- 把业务逻辑抽到Presenter中去,避免复杂业务逻辑造成的内存泄漏。

具体实现

1.对View进行封装

一般情况下,做数据请求都有显示加载框、请求成功、请求失败等操作,我们把这些共有的功能封装到BaseView中。

public interface IBaseView { / 显示加载框 / void showLoading(); / 隐藏加载框 / void dismissLoading(); / 空数据 @param tag TAG / void onEmpty(Object tag); / 错误数据 @param tag TAG @param errorMsg 错误信息 / void onError(Object tag, String errorMsg); / 上下文 @return context / Context getContext();}

2.对Presenter封装

为了避免持有View的Presenter做耗时操作而引起的内存泄漏,我们的Presenter应该和宿主Activity/Fragment同创建、同销毁。

public abstract class BasePresenter{ ... / 绑定View / public void attachView(View view) { this.view=view; } / 解绑View / public void detachView() { this.view=null; } ...}public abstract class MvpActivity extends BaseActivity implements View{ ... @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //创建present presenter = createPresenter(); if (presenter != null) { presenter.attachView(this); } } @Override protected void onDestroy() { super.onDestroy(); if (presenter != null) { presenter.detachView(); presenter = null; } } ...}

如上操作固然可以解决内存泄漏问题,但又会引发新的问题:

场景:用户打开商品列表页,网络不好获取数据比较慢,用户离开该页面,继续浏览其他页面,突然应用崩溃了。

分析问题:

在用户打开页面的时候绑定P和V,离开页面的时候解绑P和V,当耗时操作完成调用V更新界面,此时由于P和V已经解绑V处于null,调用V的更新页面方法就会引起空指针异常。

解决问题:

使用动态代理对View做弱引用,完整的BasePresenter如下:

public abstract class BasePresenter<M extends IBaseModel, V extends IBaseView> { private V mProxyView; private M module; private WeakReference<V> weakReference; / 绑定View / @SuppressWarnings("unchecked") public void attachView(V view) { weakReference = new WeakReference<>(view); mProxyView = (V) Proxy.newProxyInstance( view.getClass().getClassLoader(), view.getClass().getInterfaces(), new MvpViewHandler(weakReference.get())); if (this.module == null) { this.module = createModule(); } } / 解绑View / public void detachView() { this.module = null; if (isViewAttached()) { weakReference.clear(); weakReference = null; } } / 是否与View建立连接 / protected boolean isViewAttached() { return weakReference != null && weakReference.get() != null; } protected V getView() { return mProxyView; } protected M getModule() { return module; } protected Context getContext() { return getView().getContext(); } protected void showLoading() { getView().showLoading(); } protected void dismissLoading() { getView().dismissLoading(); } / 通过该方法创建Module / protected abstract M createModule(); / 初始化方法 / public abstract void start(); / View代理类 防止 页面关闭P异步操作调用V 方法 空指针问题 / private class MvpViewHandler implements InvocationHandler { private IBaseView mvpView; MvpViewHandler(IBaseView mvpView) { this.mvpView = mvpView; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //如果V层没被销毁, 执行V层的方法. if (isViewAttached()) { return method.invoke(mvpView, args); } //P层不需要关注V层的返回值 return null; } }}

3.契约类Contract的出现

通过契约类来管理Model、View、Presenter的所有接口,这样使得Presenter和View有哪些功能一目了然,维护起来也方便,同时使得View与Presenter一一对应,并有效地减少类的数目。

public interface Contract { interface Model extends IBaseModel { void login(User user, ResponseCallback callback); } interface View extends IBaseView { User getUserInfo(); void loginSuccess(User user); } interface Presenter { void login(); }}

4.对Activity的封装,Fragment封装同理

public abstract class BaseMvpActivity<P extends BasePresenter> extends Activity implements IBaseView { protected P presenter; @SuppressWarnings("unchecked") @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //创建present presenter = createPresenter(); if (presenter != null) { presenter.attachView(this); } } @Override protected void onDestroy() { super.onDestroy(); if (presenter != null) { presenter.detachView(); presenter = null; } } @Override public void showLoading() { if (loadingDialog != null && !loadingDialog.isShowing()) { loadingDialog.show(); } } @Override public void dismissLoading() { if (loadingDialog != null && loadingDialog.isShowing()) { loadingDialog.dismiss(); } } @Override public void onEmpty(Object tag) { } @Override public void onError(Object tag, String errorMsg) { } @Override public Context getContext() { return mContext; } / 创建Presenter / protected abstract P createPresenter();}

通过泛型规定Presenter,并且暴露抽象方法createPresenter()给子类来创建Presenter,基类实现BaseView中的公共方法,减少子类代码的冗余。

5.登录案例

Contract(契约类)

public interface LoginContract { interface Model extends IBaseModel { / 登录 @param user 用户信息 @param callback 回调 / void login(User user, ResponseCallback callback); } interface View extends IBaseView { / 返回用户信息 / User getUserInfo(); / 登录成功 / void loginSuccess(User user); } interface Presenter { / 登录 / void login(); }}

Model(数据层)

public class LoginModel implements LoginContract.Model { @Override public void login(User user, ResponseCallback callback) { if (user == null) { callback.onError("", (Throwable) new Exception("用户信息为空")); } RequestParam param = new RequestParam(); param.addParameter("username", user.getUsername()); param.addParameter("password", user.getPassword()); HttpUtils.getInstance() .postRequest(Api.LOGIN, param, callback); }}

Presenter(控制器)

public class LoginPresenter extends BasePresenter<LoginContract.Model, LoginContract.View> implements LoginContract.Presenter { @Override public void login() { if (isViewAttached()) { getView().showLoading(); getModule().login(getView().getUserInfo(), new OnResultObjectCallBack<User>() { @Override public void onSuccess(boolean success, int code, String msg, Object tag, User response) { if (code == 0 && response != null) { getView().loginSuccess(response); } else { getView().onError(tag, msg); } } @Override public void onFailure(Object tag, Exception e) { getView().onError(tag, msg); } @Override public void onCompleted() { getView().dismissLoading(); } }); } } @Override protected LoginModel createModule() { return new LoginModel(); } @Override public void start() { }}

登录Activity

public class LoginActivity extends ActionBarActivity<LoginPresenter> implements LoginContract.View { @BindView(R2.id.edt_name) EditText edtName; @BindView(R2.id.edt_pwd) EditText edtPwd; @BindView(R2.id.ob_login) ObserverButton obLogin; @BindView(R2.id.ob_register) TextView obRegister; @Override protected int getLayoutId() { return R.layout.user_activity_login; } @Override protected void initView() { setTitleText("登录"); obLogin.observer(edtName, edtPwd); } @OnClick({R2.id.ob_login, R2.id.ob_register}) public void onViewClicked(View view) { int i = view.getId(); if (i == R.id.ob_login) { presenter.login(); } else if (i == R.id.ob_register) { ActivityToActivity.toActivity(mContext, RegisterActivity.class); } } @Override public void loginSuccess(User user) { UserInfoUtils.saveUser(user); EventBusUtils.sendEvent(new Event(EventAction.EVENT_LOGIN_SUCCESS)); finish(); } @Override public void onError(Object tag, String errorMsg) { super.onError(tag, errorMsg); ToastUtils.showToast(mContext, errorMsg); } @Override protected LoginPresenter createPresenter() { return new LoginPresenter(); } @Override public void onEventBus(Event event) { super.onEventBus(event); if (TextUtils.equals(event.getAction(), EventAction.EVENT_REGISTER_SUCCESS)) { finish(); } } @Override protected boolean regEvent() { return true; } @Override public User getUserInfo() { return new User(edtName.getText().toString().trim(), edtPwd.getText().toString().trim()); }}总结

无论是MVP还是MCV或者MVVM,都是为把业务与UI分离,避免在一个Activity里把所有的操作都塞进来,各自在各自的领域工作。
每个人对于层级结构都有不同的理解和看法,封装一个适合自己、适合当下业务场景的框架才是最重要的。

这里的框架中所使用的就是MVP结构

本 Demo下载下来后common_base模块可直接使用。

头条不允许内嵌GitHub的网址 所以无法配置超链接 需要源码的小伙伴可以留言,无偿奉献给小伙伴们!

相关文章

IT主流项目介绍,创新驱动,引领未来

随着科技的飞速发展,信息技术(IT)行业正成为推动全球经济增长的重要力量。近年来,IT主流项目层出不穷,为各行各业带来了革命性的变...

软件开发 2025-01-01 阅读0 评论0

语言翻译失误,一场跨文化的误会与反思

在全球化日益深入的今天,语言翻译作为文化交流的桥梁,发挥着至关重要的作用。由于语言、文化、语境等因素的复杂性,翻译失误现象时有发生...

软件开发 2025-01-01 阅读0 评论0

语言与大脑,介绍人脑处理语言的奥秘

语言是人类沟通的重要工具,也是人类文明的基石。人脑处理语言的过程错综复杂,涉及到多个脑区的协同工作。本文将探讨人脑处理语言的奥秘,...

软件开发 2025-01-01 阅读0 评论0