是我的MVP有效的实现模式



我是Android和MVP的新手,在过去的一年半里我一直在做iOS编程,所以我发现委托模式很容易消化。我以这样一种方式实现了MVP,视图符合演示者的协议,这让演示者忽略视图的特定类型,但让它知道某些方法是给定的,因此可以在"视图"上调用。我一直在阅读各种MVP指南,以及所有的Mosby教程,我不确定我是否同意其中的一些。我所实现的模式是犹太的吗?我想要一些反馈,这样我就不会一直朝着不好的方向前进,如果这确实是我正在做的…

例如,

基地推荐者:

public abstract class Presenter<V, S> implements BasePresenterInterface<V, S> {
    public interface PresenterProtocol extends BasePresenterProtocol {
    }
    private WeakReference<V> mAttachedView = null;
    private S mService = null;
    /**
     * Interface Overrides
     */
    @Override
    public void attachView(V view) {
        boolean viewDoesNotConform = !viewDoesConform(view);
        if (viewDoesNotConform) {
            Log.d("DEBUG", "Cannot attach View that does not conform to PresenterProtocol");
            return;
        }
        mAttachedView = new WeakReference<>(view);
        ((BasePresenterProtocol) getAttachedView()).onViewAttached();
    }
    @Override
    public void detachView() {
        mAttachedView = null;
    }
    @Override
    public boolean viewDoesConform(V view) {
        Class<?> klass    = view.getClass();
        boolean  conforms = BasePresenterInterface.BasePresenterProtocol.class.isAssignableFrom(klass);
        return conforms;
    }
    @Override
    public boolean viewIsAttached() {
        return mAttachedView != null;
    }
    @Override
    public V getAttachedView() {
        return mAttachedView.get();
    }
    @Override
    public S getService() {
        return mService;
    }
    @Override
    public void setService(S service) {
        mService = service;
    }
}

然后将其子类化为如下:

PhotoRecyclerPresenter:

public class PhotoRecyclerPresenter extends Presenter<PhotoRecyclerPresenter.PhotoRecyclerPresenterProtocol, PhotoService> {
    public interface PhotoRecyclerPresenterProtocol extends Presenter.PresenterProtocol {
        void onPhotosLoaded(List<TestPhoto> photoList);
        void onItemSelected(TestPhoto photo);
        void onShowDetail(TestPhoto photo);
    }
    private static PhotoRecyclerPresenter mSharedInstance;
    private PhotoRecyclerPresenter() {
        setService(new PhotoService());
    }
    /**
     * External Methods
     */
    public void getPhotos() {
        boolean noAttachedView = !viewIsAttached();
        if (noAttachedView) {
            Log.d("DEBUG", "No view attached");
            return;
        }
        getService().getAPI()
                    .getPhotos()
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(photoList -> getAttachedView().onPhotosLoaded(photoList));
    }

    /**
     * Internal Methods
     */
    public static PhotoRecyclerPresenter getSharedInstance() {
        boolean firstInstance = mSharedInstance == null;
        if (firstInstance) {
            setSharedInstance(new PhotoRecyclerPresenter());
        }
        return mSharedInstance;
    }
    public static void setSharedInstance(PhotoRecyclerPresenter instance) {
        mSharedInstance = instance;
    }
    public void didSelectItem(TestPhoto photo) {
        getAttachedView().showDetail(photo);
    }
}

它与视图通信: PhotoRecyclerFragment:

public class PhotoRecyclerFragment extends Fragment implements PhotoRecyclerPresenter.PhotoRecyclerPresenterProtocol {
    private RecyclerView               mRecyclerView;
    private RecyclerView.LayoutManager mLayoutManager;
    private Activity                   mParentActivity;
    private PhotoRecyclerPresenter     mPresenter;
    private PhotoRecyclerAdapter mAdapter;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_recycler, container, false);
        mParentActivity = getActivity();
        mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
        mLayoutManager = new LinearLayoutManager(mParentActivity);
        mAdapter = new PhotoRecyclerAdapter(this);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setAdapter(mAdapter);
        mPresenter = PhotoRecyclerPresenter.getSharedInstance();
        mPresenter.attachView(this);
        return rootView;
    }
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mPresenter.detachView();
        mAdapter.clear();
    }

    /**
     * PhotoRecyclerPresenterProtocol Methods
     */

    @Override
    public void onItemSelected(TestPhoto photo) {
        mPresenter.didSelectItem(photo);
    }
    @Override
    public void onPhotosLoaded(List<TestPhoto> photoList) {
        mAdapter.loadPhotos(photoList);
    }
    @Override
    public void onViewAttached() {
        mPresenter.getPhotos();
    }
    @Override
    public void onViewDetached() {
    }
    @Override
    public void onShowDetail(TestPhoto photo) {
        Intent detailIntent = new Intent(mParentActivity, PhotoDetailActivity.class);
        mParentActivity.startActivity(detailIntent.putExtra(Intent.EXTRA_UID, photo.getPhotoId()));
    }
}

这让我定义了一组视图需要遵守的要求,以便使用单例呈现器,同时保持呈现器不知道哪些视图使用它,只要它们符合它的协议。到目前为止,在我的实践项目中,它似乎工作得很好,但我似乎找不到任何资源,在那里我正在做的事情被推荐为MVP,我有足够的自我怀疑,我想我会问我的第一个StackOverflow问题。有MVP经验的人能解释一下吗?

另外,如果我问错了地方,请告诉我正确的地方。

谢谢:)

在我看来,你正在做和Mosby做的一样的事情。唯一的区别是接口(或objective-c中的协议)的名称。你叫它PresenterProtocol,而莫斯比叫它MvpView。两者都在做同样的工作:为Presenter提供演示者可以调用的方法Api来操作视图。

唯一没有意义的是有一个方法viewDoesConform()。在Java中有类型安全。你可以使用你的演示器的泛型类型V来确保你的片段正在实现演示器的协议。把它改成V extends BasePresentersProtocol

此外,我认为拥有演示者的"共享实例"(也称为单例模式)是没有意义的。我认为拥有PhotoService的"共享实例"会更有意义。但也请注意,这样做你的代码是不可测试的(单元测试)了。你应该谷歌一下"依赖注入"或"控制逆",了解如何编写模块化、可重用和可测试的代码。我说的不是像Dagger、spring或guice这样的依赖注入框架。您只需要理解依赖注入背后的思想。你可以完全按照这个原则编写类,而不需要依赖注入框架(即使用构造函数参数)。

旁注:你永远不能从PhotoService取消订阅你的演示者。根据PhotoService的实现方式,你可能会有内存泄漏,因为PhotoService的可观察对象有一个对演示者的引用,这会阻止演示者和PhotoService(取决于你的具体实现)被垃圾收集。

编辑:Mosby定义了View的协议。请查看项目网站上的入门部分。HelloWorldView定义了两个方法:showHello()showGoodbye()(由HelloWorldActivity实现),HelloWorldPresenter调用这两个方法来操作视图。HelloWorldPresenter还取消异步请求以避免内存泄漏。你也应该这样做。否则,你的演示器只能在改造httpcall完成后被垃圾收集。

最新更新