具有多个片段的活动的 MVP

Posted

技术标签:

【中文标题】具有多个片段的活动的 MVP【英文标题】:MVP for Activity with multiple Fragments 【发布时间】:2016-03-19 09:26:51 【问题描述】:

我有一个包含两个片段的活动。

活动 (MainActivity) 从开放的天气 API 中检索数据。我为此实施了 MVP,其中: Model 包含来自 API 的所有响应对象ViewActivityPresenter 包含 MainPresenterMainPresenterImplMainViewGetDataInteractorGetDataInteractorImpl

因此,活动从 Web 服务获取数据。两个片段都将显示活动中检索到的数据中的数据。

在这种情况下使用 MVP 的最佳做法是什么?我知道如何通过接口/回调在片段 活动之间传递数据,我的问题是在实现 MVP 时这种行为会改变吗?

【问题讨论】:

只是一个想法:我会考虑将片段计为视图(关于 MVP),因此我想知道让一个演示者引用多个视图(或者更确切地说:它们的接口回调)是否会很奇怪) 在最适合的视图中显示不同的数据?我认为演示者需要决定/指导哪个视图显示哪些数据?显然,一个视图的多个演示者是一种有效的方法,所以也许另一种方法也可以:***.com/a/2068/1041533 @AgentKnopf 实际上,正如 MVP 中的 programmers.stackexchange.com/a/261351/206366 所述,每个演示者负责呈现一个视图。演示者可以呈现多个视图的唯一方法是,如果不同的视图只是绑定到演示者的单个视图接口的不同实现。 @Ari 感谢您的跟进 - 这确实有道理! 【参考方案1】:

应将活动/片段视为 MVP 模型中的视图。这意味着他们应该只显示数据并接收用户交互。 可以通过接口/回调来交流活动和片段。

但是,调用 API 服务不是活动/片段的责任。

presenter 应该负责调用 api 服务。

因此,演示者应该公开一个类似loadXXX 的方法,在内部它会调用服务。收到响应后,演示者应使用服务结果调用view.showXXX。活动/片段应调用此loadXXX 方法并实现showXXX

通常,演示者被创建或注入到活动/片段中。 Activity/Fragment必须实现Presenter暴露的接口,Presenter持有该接口的弱引用,以便回调。

当用户与屏幕交互时,例如按钮上的onClick,activity/fragment 会调用presenter 中的相应方法,例如presenter.loadUserDetails() 演示者告诉视图显示为正在加载,例如view.showAsLoading() 因为它必须做自己的事情:可能验证某些内容或从 api 服务加载数据,最后将结果回调到视图,例如view.showUserDetails(userDetails).

总结,一个例子,在MVP的各个部分的代码中:

Activity/Fragment 仅代表 MVP 的 View:

public class MyActivity extends AppCompatActivity implements MyPresenter.View 
    private MyPresenter mPresenter;

    public onCreate() 
        ...
        mPresenter = new MyPresenter(this); // Or inject it and then set the view.
    

    public void onClick(View v) 
        mPresenter.loadXXX(param1, param2);
    

    // MyPresenter.View methods

    public void showAsLoading() 
        ...
    

    public void showUserDetails(UserDetails userDetails) 
        ...
    

型号:

public class UserDetails 
    ...

演讲者:

public class MyPresenter 

    private WeakReference<MyPresenter.View> mWeakView;

    public MyPresenter(MyPresenter.View view) 
        mWeakView = new WeakReference(view);
    

    public void loadXXX(String param1, String param2) 
        MyPresenter.View view = mWeakView.get();
        if (view != null) 
            view.showAsLoading();
            // Do stuff, e.g. make the Api call and finally call view.showUserDetails(userDetails);
        
    

    interface View 
        void showAsLoading();
        void showUserDetails(UserDetails userDetails);
    


【讨论】:

先生,您能解释一下为什么 mWeakView 是 WeakReference,原因是什么? 这是为了避免保留对 Activity/Fragment 的引用。演示者向 API 发出异步请求。如果您在演示者发出请求时按下或完成活动并且您不使用弱引用,则演示者将保留 Activity/Fragment 内存(保留该 Activity/Fragment 的所有视图和成员)。除了使用 Wea​​kReference,在演示者中公开附加和分离方法也很常见。实例化presenter后你应该调用attach方法,当Activity/Fragment的onDestroy被调用时,你应该调用detach。 如果您不使用 Wea​​kReference 或附加/分离方法,并且您的活动/片段在演示者的请求完成之前被销毁,您也可能在请求完成时遇到问题,因为它会尝试在被破坏的活动/片段上更新一些东西。 我正在做附加/分离的事情。同样当应用暂停时,我正在停止所有网络通话,不知道是否正确 @ShobhitPuri 是的,绝对是。所有与 UI 相关的事情都必须在 View 层中完成:活动和片段。根据经验,您不应该在演示者中有任何 android 导入。

以上是关于具有多个片段的活动的 MVP的主要内容,如果未能解决你的问题,请参考以下文章

开发具有多个活动或一个活动和多个片段的应用程序?

Android MVVM:具有多个片段的活动 - 将共享 LiveData 放在哪里?

从单个按钮从多个片段中提取数据

一个活动或单独活动中的多个片段

Kotlin 相同片段多个活动

在单个活动中动态实现多个片段