泛型类型接口实现:保障MvpView与MvpPresenter匹配的安全方案咨询
嘿,我正好在MVP架构实践中碰到过完全一样的问题,咱们一步步拆解解决这两个核心痛点:
1. 编译期确保子类绑定正确的MvpView类型(消除安全隐患)
你提到的“无法确保子类实现对应P型Presenter所需的正确MvpView”,本质是泛型约束缺失导致的编译期检查缺位。我们可以通过给BasePresenter绑定专属的View泛型来解决:
首先,重新定义你的BasePresenter,让它强制关联一个特定的MvpView子类:
public abstract class BasePresenter<V extends MvpView> { // 持有当前关联的View实例 private V mAttachedView; // 对外暴露的attach方法,强制传入指定类型的View public final void attachView(V view) { if (view == null) { throw new IllegalArgumentException("View cannot be null!"); } this.mAttachedView = view; // 子类可以实现这个方法处理attach后的自定义逻辑 onViewAttached(); } // 子类可选实现的attach回调 protected void onViewAttached() {} // 统一的detach方法 public final void detachView() { this.mAttachedView = null; onViewDetached(); } // 子类可选实现的detach回调 protected void onViewDetached() {} // 安全获取View的方法,避免空指针 protected final V getView() { if (mAttachedView == null) { throw new IllegalStateException("View is not attached to presenter!"); } return mAttachedView; } }
然后,子类Presenter必须明确指定自己对应的View类型,比如LoginPresenter只能关联LoginView:
// 这里泛型<V>必须是MvpView的子类,且是当前Presenter专属的View public class LoginPresenter extends BasePresenter<LoginView> { @Override protected void onViewAttached() { // 这里写原来需要在attach后执行的逻辑,不用重复写attach代码 } // 业务示例方法:安全调用View的方法 public void handleLogin(String username) { getView().showLoginProgress(); // 后续业务逻辑... } }
这样一来,如果有人不小心让LoginPresenter继承BasePresenter<OtherView>,编译器会直接报错,从根源杜绝了绑定错误View的安全隐患。
2. 自动处理attach逻辑,消除重复代码
要避免每个子类都手动写presenter.attach(this),我们可以把attach/detach逻辑下沉到View层的基类(比如BaseActivity/BaseFragment)中:
先定义一个MVP专属的View基类:
public abstract class BaseMvpActivity<V extends MvpView, P extends BasePresenter<V>> extends AppCompatActivity implements V { protected P mPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 让子类提供Presenter实例 mPresenter = createPresenter(); // 自动完成attach,这里的强转因为泛型约束是安全的 mPresenter.attachView((V) this); } @Override protected void onDestroy() { super.onDestroy(); // 自动完成detach,避免内存泄漏 mPresenter.detachView(); } // 子类必须实现这个方法,返回对应的Presenter实例 protected abstract P createPresenter(); }
然后你的业务View(比如LoginActivity)只需要继承这个基类并实现对应接口:
// 明确指定当前View是LoginView,Presenter是LoginPresenter public class LoginActivity extends BaseMvpActivity<LoginView, LoginPresenter> implements LoginView { @Override protected LoginPresenter createPresenter() { return new LoginPresenter(); } // 实现LoginView的方法 @Override public void showLoginProgress() { // 显示加载框逻辑 } }
现在,所有继承BaseMvpActivity的业务页面都不用再手动写attach(this),基类会自动在onCreate中完成绑定,在onDestroy中完成解绑,既消除了重复代码,还能避免忘记detach导致的内存泄漏。
内容的提问来源于stack exchange,提问作者alfoks
相关产品推荐
相关产品推荐

